Compensate for changes in JDK 7 Introspector
Prior to JDK 7, java.beans.Introspector registered indexed write methods
irrespective of return type, for example either of the following methods
were legal
void setFoo(int i, Foo foo)
Object setFoo(int i, Foo foo)
This was considered a bug and disallowed starting with JDK 7, such that
only the former signature is a candidate.
Supporting non-void returning setter methods is exactly what
ExtendedBeanInfo was designed to do, and prior to this commit, the
implementation of ExtendedBeanInfo assumed this (somewhat surprising)
behavior from the underlying Introspector, and because it worked out of
the box, took no extra steps to recognize and register these methods.
For this reason, non-void returning indexed write methods were not
registered under JDK 7+, causing test failures in ExtendedBeanInfoTests.
Now the implementation is careful to detect these methods without any
assumption about Introspector behavior, such that they are registered in
exactly the same fashion across JDK versions.
Issue: SPR-9014
This commit is contained in:
@@ -131,19 +131,13 @@ class ExtendedBeanInfo implements BeanInfo {
|
||||
Method indexedReadMethod = ipd.getIndexedReadMethod();
|
||||
Method indexedWriteMethod = ipd.getIndexedWriteMethod();
|
||||
// has the setter already been found by the wrapped BeanInfo?
|
||||
if (indexedWriteMethod != null
|
||||
&& indexedWriteMethod.getName().equals(method.getName())) {
|
||||
// yes -> copy it, including corresponding getter method (if any -- may be null)
|
||||
this.addOrUpdatePropertyDescriptor(pd, propertyName, readMethod, writeMethod, indexedReadMethod, indexedWriteMethod);
|
||||
continue ALL_METHODS;
|
||||
}
|
||||
// has a getter corresponding to this setter already been found by the wrapped BeanInfo?
|
||||
if (indexedReadMethod != null
|
||||
&& indexedReadMethod.getName().equals(getterMethodNameFor(propertyName))
|
||||
&& indexedReadMethod.getReturnType().equals(method.getParameterTypes()[1])) {
|
||||
this.addOrUpdatePropertyDescriptor(pd, propertyName, readMethod, writeMethod, indexedReadMethod, method);
|
||||
continue ALL_METHODS;
|
||||
if (!(indexedWriteMethod != null
|
||||
&& indexedWriteMethod.getName().equals(method.getName()))) {
|
||||
indexedWriteMethod = method;
|
||||
}
|
||||
// yes -> copy it, including corresponding getter method (if any -- may be null)
|
||||
this.addOrUpdatePropertyDescriptor(pd, propertyName, readMethod, writeMethod, indexedReadMethod, indexedWriteMethod);
|
||||
continue ALL_METHODS;
|
||||
}
|
||||
// the INDEXED setter method was not found by the wrapped BeanInfo -> add a new PropertyDescriptor
|
||||
// for it. no corresponding INDEXED getter was detected, so the 'indexed read method' parameter is null.
|
||||
@@ -293,6 +287,16 @@ class ExtendedBeanInfo implements BeanInfo {
|
||||
writeMethod, propertyName, ex.getMessage()));
|
||||
// fall through -> add property descriptor as best we can
|
||||
}
|
||||
if (pd instanceof IndexedPropertyDescriptor) {
|
||||
((IndexedPropertyDescriptor)pd).setIndexedReadMethod(indexedReadMethod);
|
||||
try {
|
||||
((IndexedPropertyDescriptor)pd).setIndexedWriteMethod(indexedWriteMethod);
|
||||
} catch (IntrospectionException ex) {
|
||||
logger.debug(format("Could not add indexed write method [%s] for property [%s]. Reason: %s",
|
||||
indexedWriteMethod, propertyName, ex.getMessage()));
|
||||
// fall through -> add property descriptor as best we can
|
||||
}
|
||||
}
|
||||
this.propertyDescriptors.add(pd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import java.lang.reflect.Method;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.ExtendedBeanInfo.PropertyDescriptorComparator;
|
||||
import org.springframework.core.JdkVersion;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import test.beans.TestBean;
|
||||
@@ -429,11 +430,12 @@ public class ExtendedBeanInfoTests {
|
||||
}
|
||||
|
||||
BeanInfo bi = Introspector.getBeanInfo(C.class);
|
||||
BeanInfo ebi = new ExtendedBeanInfo(Introspector.getBeanInfo(C.class));
|
||||
|
||||
assertThat(hasIndexedReadMethodForProperty(bi, "foos"), is(true));
|
||||
// interesting! standard Inspector picks up non-void return types on indexed write methods by default
|
||||
assertThat(hasIndexedWriteMethodForProperty(bi, "foos"), is(true));
|
||||
assertThat(hasIndexedWriteMethodForProperty(bi, "foos"), is(trueUntilJdk17()));
|
||||
|
||||
BeanInfo ebi = new ExtendedBeanInfo(Introspector.getBeanInfo(C.class));
|
||||
|
||||
assertThat(hasIndexedReadMethodForProperty(ebi, "foos"), is(true));
|
||||
assertThat(hasIndexedWriteMethodForProperty(ebi, "foos"), is(true));
|
||||
@@ -456,13 +458,12 @@ public class ExtendedBeanInfoTests {
|
||||
assertThat(hasIndexedReadMethodForProperty(bi, "foos"), is(true));
|
||||
assertThat(hasWriteMethodForProperty(bi, "foos"), is(false));
|
||||
// again as above, standard Inspector picks up non-void return types on indexed write methods by default
|
||||
assertThat(hasIndexedWriteMethodForProperty(bi, "foos"), is(true));
|
||||
assertThat(hasIndexedWriteMethodForProperty(bi, "foos"), is(trueUntilJdk17()));
|
||||
|
||||
BeanInfo ebi = new ExtendedBeanInfo(Introspector.getBeanInfo(C.class));
|
||||
|
||||
assertThat(hasIndexedReadMethodForProperty(bi, "foos"), is(true));
|
||||
assertThat(hasWriteMethodForProperty(bi, "foos"), is(true));
|
||||
// again as above, standard Inspector picks up non-void return types on indexed write methods by default
|
||||
assertThat(hasIndexedWriteMethodForProperty(bi, "foos"), is(true));
|
||||
|
||||
assertThat(hasIndexedReadMethodForProperty(ebi, "foos"), is(true));
|
||||
@@ -550,17 +551,17 @@ public class ExtendedBeanInfoTests {
|
||||
assertThat(hasReadMethodForProperty(bi, "dateFormat"), is(false));
|
||||
assertThat(hasWriteMethodForProperty(bi, "dateFormat"), is(false));
|
||||
assertThat(hasIndexedReadMethodForProperty(bi, "dateFormat"), is(false));
|
||||
assertThat(hasIndexedWriteMethodForProperty(bi, "dateFormat"), is(true));
|
||||
assertThat(hasIndexedWriteMethodForProperty(bi, "dateFormat"), is(trueUntilJdk17()));
|
||||
|
||||
ExtendedBeanInfo ebi = new ExtendedBeanInfo(bi);
|
||||
|
||||
assertThat(hasReadMethodForProperty(bi, "dateFormat"), is(false));
|
||||
assertThat(hasWriteMethodForProperty(bi, "dateFormat"), is(true));
|
||||
assertThat(hasWriteMethodForProperty(bi, "dateFormat"), is(false));
|
||||
assertThat(hasIndexedReadMethodForProperty(bi, "dateFormat"), is(false));
|
||||
assertThat(hasIndexedWriteMethodForProperty(bi, "dateFormat"), is(true));
|
||||
assertThat(hasIndexedWriteMethodForProperty(bi, "dateFormat"), is(trueUntilJdk17()));
|
||||
|
||||
assertThat(hasReadMethodForProperty(ebi, "dateFormat"), is(false));
|
||||
assertThat(hasWriteMethodForProperty(ebi, "dateFormat"), is(true));
|
||||
assertThat(hasWriteMethodForProperty(ebi, "dateFormat"), is(false));
|
||||
assertThat(hasIndexedReadMethodForProperty(ebi, "dateFormat"), is(false));
|
||||
assertThat(hasIndexedWriteMethodForProperty(ebi, "dateFormat"), is(true));
|
||||
}
|
||||
@@ -663,6 +664,10 @@ public class ExtendedBeanInfoTests {
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean trueUntilJdk17() {
|
||||
return JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_17;
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void reproSpr8806() throws IntrospectionException {
|
||||
|
||||
Reference in New Issue
Block a user