Fixed detection of setter in case of getter with covariant return type narrowing

Issue: SPR-10995
This commit is contained in:
Juergen Hoeller
2013-10-26 15:14:31 +02:00
parent 42568afb37
commit 045f78e6c5
4 changed files with 81 additions and 36 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,32 +31,32 @@ import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
* Extension of the standard JavaBeans PropertyDescriptor class,
* overriding {@code getPropertyType()} such that a generically
* declared type will be resolved against the containing bean class.
* Extension of the standard JavaBeans {@link PropertyDescriptor} class,
* overriding {@code getPropertyType()} such that a generically declared
* type variable will be resolved against the containing bean class.
*
* @author Juergen Hoeller
* @since 2.5.2
*/
class GenericTypeAwarePropertyDescriptor extends PropertyDescriptor {
private final Class beanClass;
private final Class<?> beanClass;
private final Method readMethod;
private final Method writeMethod;
private final Class propertyEditorClass;
private final Class<?> propertyEditorClass;
private volatile Set<Method> ambiguousWriteMethods;
private Class propertyType;
private Class<?> propertyType;
private MethodParameter writeMethodParameter;
public GenericTypeAwarePropertyDescriptor(Class beanClass, String propertyName,
Method readMethod, Method writeMethod, Class propertyEditorClass)
public GenericTypeAwarePropertyDescriptor(Class<?> beanClass, String propertyName,
Method readMethod, Method writeMethod, Class<?> propertyEditorClass)
throws IntrospectionException {
super(propertyName, null, null);
@@ -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;
@@ -118,12 +121,12 @@ class GenericTypeAwarePropertyDescriptor extends PropertyDescriptor {
}
@Override
public Class getPropertyEditorClass() {
public Class<?> getPropertyEditorClass() {
return this.propertyEditorClass;
}
@Override
public synchronized Class getPropertyType() {
public synchronized Class<?> getPropertyType() {
if (this.propertyType == null) {
if (this.readMethod != null) {
this.propertyType = GenericTypeResolver.resolveReturnType(this.readMethod, this.beanClass);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -71,6 +71,11 @@ public class DerivedTestBean extends TestBean implements Serializable, BeanNameA
setSpouse(new TestBean(name));
}
@Override
public TestBean getSpouse() {
return (TestBean) super.getSpouse();
}
public void initialize() {
this.initialized = true;

View File

@@ -35,11 +35,10 @@
</property>
</bean>
<bean id="pJenny" class="org.springframework.tests.sample.beans.TestBean" scope="prototype">
<bean id="pJenny" class="org.springframework.tests.sample.beans.DerivedTestBean" scope="prototype">
<property name="name"><value>Jenny</value></property>
<property name="age"><value>30</value></property>
<property name="spouse">
<!-- Could use id and href -->
<ref local="david"/>
</property>
</bean>