Skip to content

Commit ce2f28d

Browse files
committed
CachedIntrospectionResults explicitly introspects implemented interfaces (for Java 8 default methods)
Issue: SPR-14198
1 parent 335d968 commit ce2f28d

File tree

2 files changed

+47
-3
lines changed

2 files changed

+47
-3
lines changed

spring-beans/src/main/java/org/springframework/beans/CachedIntrospectionResults.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -303,6 +303,24 @@ private CachedIntrospectionResults(Class<?> beanClass) throws BeansException {
303303
this.propertyDescriptorCache.put(pd.getName(), pd);
304304
}
305305

306+
// Explicitly check implemented interfaces for setter/getter methods as well,
307+
// in particular for Java 8 default methods...
308+
Class<?> clazz = beanClass;
309+
while (clazz != null) {
310+
Class<?>[] ifcs = clazz.getInterfaces();
311+
for (Class<?> ifc : ifcs) {
312+
BeanInfo ifcInfo = Introspector.getBeanInfo(ifc, Introspector.IGNORE_ALL_BEANINFO);
313+
PropertyDescriptor[] ifcPds = ifcInfo.getPropertyDescriptors();
314+
for (PropertyDescriptor pd : ifcPds) {
315+
if (!this.propertyDescriptorCache.containsKey(pd.getName())) {
316+
pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd);
317+
this.propertyDescriptorCache.put(pd.getName(), pd);
318+
}
319+
}
320+
}
321+
clazz = clazz.getSuperclass();
322+
}
323+
306324
this.typeDescriptorCache = new ConcurrentReferenceHashMap<PropertyDescriptor, TypeDescriptor>();
307325
}
308326
catch (IntrospectionException ex) {

spring-beans/src/test/java/org/springframework/beans/BeanWrapperTests.java

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -61,6 +61,14 @@ public void getterSilentlyFailWithOldValueExtraction() {
6161
assertTrue("Set name to tom", target.getName().equals("tom"));
6262
}
6363

64+
@Test
65+
public void aliasedSetterThroughDefaultMethod() {
66+
GetterBean target = new GetterBean();
67+
BeanWrapper accessor = createAccessor(target);
68+
accessor.setPropertyValue("aliasedName", "tom");
69+
assertTrue("Set name to tom", target.getAliasedName().equals("tom"));
70+
}
71+
6472
@Test
6573
public void setValidAndInvalidPropertyValuesShouldContainExceptionDetails() {
6674
TestBean target = new TestBean();
@@ -196,7 +204,24 @@ public void getPropertyWithOptionalAndAutoGrow() {
196204

197205

198206
@SuppressWarnings("unused")
199-
private static class GetterBean {
207+
private interface AliasedProperty {
208+
209+
default void setAliasedName(String name) {
210+
setName(name);
211+
}
212+
213+
default String getAliasedName() {
214+
return getName();
215+
}
216+
217+
void setName(String name);
218+
219+
String getName();
220+
}
221+
222+
223+
@SuppressWarnings("unused")
224+
private static class GetterBean implements AliasedProperty {
200225

201226
private String name;
202227

@@ -212,6 +237,7 @@ public String getName() {
212237
}
213238
}
214239

240+
215241
@SuppressWarnings("unused")
216242
private static class IntelliBean {
217243

0 commit comments

Comments
 (0)