From 0a5392e37d268d4df9526216531a6655e52b9f38 Mon Sep 17 00:00:00 2001 From: Chris Beams Date: Mon, 13 Feb 2012 13:51:14 +0100 Subject: [PATCH] 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 --- .../beans/ExtendedBeanInfo.java | 28 +++++++++++-------- .../beans/ExtendedBeanInfoTests.java | 21 ++++++++------ 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/ExtendedBeanInfo.java b/org.springframework.beans/src/main/java/org/springframework/beans/ExtendedBeanInfo.java index ef9a3a9414..211d1803ec 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/ExtendedBeanInfo.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/ExtendedBeanInfo.java @@ -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); } } diff --git a/org.springframework.beans/src/test/java/org/springframework/beans/ExtendedBeanInfoTests.java b/org.springframework.beans/src/test/java/org/springframework/beans/ExtendedBeanInfoTests.java index ea4e783305..2049039a03 100644 --- a/org.springframework.beans/src/test/java/org/springframework/beans/ExtendedBeanInfoTests.java +++ b/org.springframework.beans/src/test/java/org/springframework/beans/ExtendedBeanInfoTests.java @@ -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 {