Skip to content

Commit 0a5392e

Browse files
committed
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
1 parent b787a68 commit 0a5392e

File tree

2 files changed

+29
-20
lines changed

2 files changed

+29
-20
lines changed

org.springframework.beans/src/main/java/org/springframework/beans/ExtendedBeanInfo.java

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -131,19 +131,13 @@ public ExtendedBeanInfo(BeanInfo delegate) throws IntrospectionException {
131131
Method indexedReadMethod = ipd.getIndexedReadMethod();
132132
Method indexedWriteMethod = ipd.getIndexedWriteMethod();
133133
// has the setter already been found by the wrapped BeanInfo?
134-
if (indexedWriteMethod != null
135-
&& indexedWriteMethod.getName().equals(method.getName())) {
136-
// yes -> copy it, including corresponding getter method (if any -- may be null)
137-
this.addOrUpdatePropertyDescriptor(pd, propertyName, readMethod, writeMethod, indexedReadMethod, indexedWriteMethod);
138-
continue ALL_METHODS;
139-
}
140-
// has a getter corresponding to this setter already been found by the wrapped BeanInfo?
141-
if (indexedReadMethod != null
142-
&& indexedReadMethod.getName().equals(getterMethodNameFor(propertyName))
143-
&& indexedReadMethod.getReturnType().equals(method.getParameterTypes()[1])) {
144-
this.addOrUpdatePropertyDescriptor(pd, propertyName, readMethod, writeMethod, indexedReadMethod, method);
145-
continue ALL_METHODS;
134+
if (!(indexedWriteMethod != null
135+
&& indexedWriteMethod.getName().equals(method.getName()))) {
136+
indexedWriteMethod = method;
146137
}
138+
// yes -> copy it, including corresponding getter method (if any -- may be null)
139+
this.addOrUpdatePropertyDescriptor(pd, propertyName, readMethod, writeMethod, indexedReadMethod, indexedWriteMethod);
140+
continue ALL_METHODS;
147141
}
148142
// the INDEXED setter method was not found by the wrapped BeanInfo -> add a new PropertyDescriptor
149143
// for it. no corresponding INDEXED getter was detected, so the 'indexed read method' parameter is null.
@@ -293,6 +287,16 @@ private void addOrUpdatePropertyDescriptor(PropertyDescriptor pd, String propert
293287
writeMethod, propertyName, ex.getMessage()));
294288
// fall through -> add property descriptor as best we can
295289
}
290+
if (pd instanceof IndexedPropertyDescriptor) {
291+
((IndexedPropertyDescriptor)pd).setIndexedReadMethod(indexedReadMethod);
292+
try {
293+
((IndexedPropertyDescriptor)pd).setIndexedWriteMethod(indexedWriteMethod);
294+
} catch (IntrospectionException ex) {
295+
logger.debug(format("Could not add indexed write method [%s] for property [%s]. Reason: %s",
296+
indexedWriteMethod, propertyName, ex.getMessage()));
297+
// fall through -> add property descriptor as best we can
298+
}
299+
}
296300
this.propertyDescriptors.add(pd);
297301
}
298302
}

org.springframework.beans/src/test/java/org/springframework/beans/ExtendedBeanInfoTests.java

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434

3535
import org.junit.Test;
3636
import org.springframework.beans.ExtendedBeanInfo.PropertyDescriptorComparator;
37+
import org.springframework.core.JdkVersion;
3738
import org.springframework.util.ClassUtils;
3839

3940
import test.beans.TestBean;
@@ -429,11 +430,12 @@ class C {
429430
}
430431

431432
BeanInfo bi = Introspector.getBeanInfo(C.class);
432-
BeanInfo ebi = new ExtendedBeanInfo(Introspector.getBeanInfo(C.class));
433433

434434
assertThat(hasIndexedReadMethodForProperty(bi, "foos"), is(true));
435435
// interesting! standard Inspector picks up non-void return types on indexed write methods by default
436-
assertThat(hasIndexedWriteMethodForProperty(bi, "foos"), is(true));
436+
assertThat(hasIndexedWriteMethodForProperty(bi, "foos"), is(trueUntilJdk17()));
437+
438+
BeanInfo ebi = new ExtendedBeanInfo(Introspector.getBeanInfo(C.class));
437439

438440
assertThat(hasIndexedReadMethodForProperty(ebi, "foos"), is(true));
439441
assertThat(hasIndexedWriteMethodForProperty(ebi, "foos"), is(true));
@@ -456,13 +458,12 @@ class C {
456458
assertThat(hasIndexedReadMethodForProperty(bi, "foos"), is(true));
457459
assertThat(hasWriteMethodForProperty(bi, "foos"), is(false));
458460
// again as above, standard Inspector picks up non-void return types on indexed write methods by default
459-
assertThat(hasIndexedWriteMethodForProperty(bi, "foos"), is(true));
461+
assertThat(hasIndexedWriteMethodForProperty(bi, "foos"), is(trueUntilJdk17()));
460462

461463
BeanInfo ebi = new ExtendedBeanInfo(Introspector.getBeanInfo(C.class));
462464

463465
assertThat(hasIndexedReadMethodForProperty(bi, "foos"), is(true));
464466
assertThat(hasWriteMethodForProperty(bi, "foos"), is(true));
465-
// again as above, standard Inspector picks up non-void return types on indexed write methods by default
466467
assertThat(hasIndexedWriteMethodForProperty(bi, "foos"), is(true));
467468

468469
assertThat(hasIndexedReadMethodForProperty(ebi, "foos"), is(true));
@@ -550,17 +551,17 @@ public void reproSpr8522() throws IntrospectionException {
550551
assertThat(hasReadMethodForProperty(bi, "dateFormat"), is(false));
551552
assertThat(hasWriteMethodForProperty(bi, "dateFormat"), is(false));
552553
assertThat(hasIndexedReadMethodForProperty(bi, "dateFormat"), is(false));
553-
assertThat(hasIndexedWriteMethodForProperty(bi, "dateFormat"), is(true));
554+
assertThat(hasIndexedWriteMethodForProperty(bi, "dateFormat"), is(trueUntilJdk17()));
554555

555556
ExtendedBeanInfo ebi = new ExtendedBeanInfo(bi);
556557

557558
assertThat(hasReadMethodForProperty(bi, "dateFormat"), is(false));
558-
assertThat(hasWriteMethodForProperty(bi, "dateFormat"), is(true));
559+
assertThat(hasWriteMethodForProperty(bi, "dateFormat"), is(false));
559560
assertThat(hasIndexedReadMethodForProperty(bi, "dateFormat"), is(false));
560-
assertThat(hasIndexedWriteMethodForProperty(bi, "dateFormat"), is(true));
561+
assertThat(hasIndexedWriteMethodForProperty(bi, "dateFormat"), is(trueUntilJdk17()));
561562

562563
assertThat(hasReadMethodForProperty(ebi, "dateFormat"), is(false));
563-
assertThat(hasWriteMethodForProperty(ebi, "dateFormat"), is(true));
564+
assertThat(hasWriteMethodForProperty(ebi, "dateFormat"), is(false));
564565
assertThat(hasIndexedReadMethodForProperty(ebi, "dateFormat"), is(false));
565566
assertThat(hasIndexedWriteMethodForProperty(ebi, "dateFormat"), is(true));
566567
}
@@ -663,6 +664,10 @@ private boolean hasIndexedReadMethodForProperty(BeanInfo beanInfo, String proper
663664
return false;
664665
}
665666

667+
private boolean trueUntilJdk17() {
668+
return JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_17;
669+
}
670+
666671

667672
@Test
668673
public void reproSpr8806() throws IntrospectionException {

0 commit comments

Comments
 (0)