diff --git a/spring-beans/src/main/java/org/springframework/beans/GenericTypeAwarePropertyDescriptor.java b/spring-beans/src/main/java/org/springframework/beans/GenericTypeAwarePropertyDescriptor.java index a290a191685..096bae5a617 100644 --- a/spring-beans/src/main/java/org/springframework/beans/GenericTypeAwarePropertyDescriptor.java +++ b/spring-beans/src/main/java/org/springframework/beans/GenericTypeAwarePropertyDescriptor.java @@ -69,8 +69,11 @@ class GenericTypeAwarePropertyDescriptor extends PropertyDescriptor { // Fallback: Original JavaBeans introspection might not have found matching setter // method due to lack of bridge method resolution, in case of the getter using a // covariant return type whereas the setter is defined for the concrete property type. - writeMethodToUse = ClassUtils.getMethodIfAvailable(this.beanClass, - "set" + StringUtils.capitalize(getName()), readMethodToUse.getReturnType()); + Method candidate = ClassUtils.getMethodIfAvailable( + this.beanClass, "set" + StringUtils.capitalize(getName()), (Class[]) null); + if (candidate != null && candidate.getParameterTypes().length == 1) { + writeMethodToUse = candidate; + } } this.readMethod = readMethodToUse; this.writeMethod = writeMethodToUse; diff --git a/spring-core/src/main/java/org/springframework/util/ClassUtils.java b/spring-core/src/main/java/org/springframework/util/ClassUtils.java index b50b875872c..0035e1ad866 100644 --- a/spring-core/src/main/java/org/springframework/util/ClassUtils.java +++ b/spring-core/src/main/java/org/springframework/util/ClassUtils.java @@ -17,15 +17,12 @@ package org.springframework.util; import java.beans.Introspector; - import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Proxy; - import java.security.AccessControlException; - import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -546,7 +543,7 @@ public abstract class ClassUtils { /** * Determine whether the given class has a public constructor with the given signature. *

Essentially translates {@code NoSuchMethodException} to "false". - * @param clazz the clazz to analyze + * @param clazz the clazz to analyze * @param paramTypes the parameter types of the method * @return whether the class has a corresponding constructor * @see Class#getMethod @@ -559,7 +556,7 @@ public abstract class ClassUtils { * Determine whether the given class has a public constructor with the given signature, * and return it if available (else return {@code null}). *

Essentially translates {@code NoSuchMethodException} to {@code null}. - * @param clazz the clazz to analyze + * @param clazz the clazz to analyze * @param paramTypes the parameter types of the method * @return the constructor, or {@code null} if not found * @see Class#getConstructor @@ -575,9 +572,9 @@ public abstract class ClassUtils { } /** - * Determine whether the given class has a method with the given signature. + * Determine whether the given class has a public method with the given signature. *

Essentially translates {@code NoSuchMethodException} to "false". - * @param clazz the clazz to analyze + * @param clazz the clazz to analyze * @param methodName the name of the method * @param paramTypes the parameter types of the method * @return whether the class has a corresponding method @@ -588,12 +585,15 @@ public abstract class ClassUtils { } /** - * Determine whether the given class has a method with the given signature, + * Determine whether the given class has a public method with the given signature, * and return it if available (else throws an {@code IllegalStateException}). + *

In case of any signature specified, only returns the method if there is a + * unique candidate, i.e. a single public method with the specified name. *

Essentially translates {@code NoSuchMethodException} to {@code IllegalStateException}. - * @param clazz the clazz to analyze + * @param clazz the clazz to analyze * @param methodName the name of the method * @param paramTypes the parameter types of the method + * (may be {@code null} to indicate any signature) * @return the method (never {@code null}) * @throws IllegalStateException if the method has not been found * @see Class#getMethod @@ -601,31 +601,69 @@ public abstract class ClassUtils { public static Method getMethod(Class clazz, String methodName, Class... paramTypes) { Assert.notNull(clazz, "Class must not be null"); Assert.notNull(methodName, "Method name must not be null"); - try { - return clazz.getMethod(methodName, paramTypes); + if (paramTypes != null) { + try { + return clazz.getMethod(methodName, paramTypes); + } + catch (NoSuchMethodException ex) { + throw new IllegalStateException("Expected method not found: " + ex); + } } - catch (NoSuchMethodException ex) { - throw new IllegalStateException("Expected method not found: " + ex); + else { + Set candidates = new HashSet(1); + Method[] methods = clazz.getMethods(); + for (Method method : methods) { + if (methodName.equals(method.getName())) { + candidates.add(method); + } + } + if (candidates.size() == 1) { + return candidates.iterator().next(); + } + else if (candidates.isEmpty()) { + throw new IllegalStateException("Expected method not found: " + clazz + "." + methodName); + } + else { + throw new IllegalStateException("No unique method found: " + clazz + "." + methodName); + } } } /** - * Determine whether the given class has a method with the given signature, + * Determine whether the given class has a public method with the given signature, * and return it if available (else return {@code null}). + *

In case of any signature specified, only returns the method if there is a + * unique candidate, i.e. a single public method with the specified name. *

Essentially translates {@code NoSuchMethodException} to {@code null}. - * @param clazz the clazz to analyze + * @param clazz the clazz to analyze * @param methodName the name of the method * @param paramTypes the parameter types of the method + * (may be {@code null} to indicate any signature) * @return the method, or {@code null} if not found * @see Class#getMethod */ public static Method getMethodIfAvailable(Class clazz, String methodName, Class... paramTypes) { Assert.notNull(clazz, "Class must not be null"); Assert.notNull(methodName, "Method name must not be null"); - try { - return clazz.getMethod(methodName, paramTypes); + if (paramTypes != null) { + try { + return clazz.getMethod(methodName, paramTypes); + } + catch (NoSuchMethodException ex) { + return null; + } } - catch (NoSuchMethodException ex) { + else { + Set candidates = new HashSet(1); + Method[] methods = clazz.getMethods(); + for (Method method : methods) { + if (methodName.equals(method.getName())) { + candidates.add(method); + } + } + if (candidates.size() == 1) { + return candidates.iterator().next(); + } return null; } } @@ -993,7 +1031,7 @@ public abstract class ClassUtils { * @param instance the instance to analyze for interfaces * @return all interfaces that the given instance implements as array */ - public static Class[] getAllInterfaces(Object instance) { + public static Class[] getAllInterfaces(Object instance) { Assert.notNull(instance, "Instance must not be null"); return getAllInterfacesForClass(instance.getClass()); }