FULL PRODUCT VERSION :
java version "1.6.0_03"
Java(TM) SE Runtime Environment (build 1.6.0_03-b05)
Java HotSpot(TM) Client VM (build 1.6.0_03-b05, mixed mode, sharing)
ADDITIONAL OS VERSION INFORMATION :
Linux danilo 2.6.22.14-72.fc6 #1 SMP Wed Nov 21 13:44:07 EST 2007 i686 i686 i386 GNU/Linux
A DESCRIPTION OF THE PROBLEM :
When a subclass overrides a superclass method with covariant return type, the BeanInfo generated by Introspector.getBeanInfo() returns the wrong method (superclass method).
Although the returned method states its "declaring class" is the subclass, the "return type" is the superclasses. This way annotations in the subclass methods are not visible.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Create a class with a getter that returns Object
2. Create a subclass that overrides that method, but returning Long
3. Call Introspector.getBeanInfo on the subclass
4. Take a look at the method of the property
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Make the behavior with covariant return types very clear or use the subclass method.
ACTUAL -
The property uses the superclass method return type with the subclass as declaring class. This is strange and even not consistent with the behavior of the Class.getMethod method. This last one, invoked on the subclass, returns the correct method (subclass method).
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
public class CovariantPropertyIntrospectionTest {
private static class Superclass {
public Object getValue() {
return null;
}
}
private class Subclass extends Superclass {
public Long getValue() {
return null;
}
}
public void verifyProperty() throws Exception {
BeanInfo beanInfo = Introspector.getBeanInfo(Subclass.class);
PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
PropertyDescriptor valueDescriptor = null;
for (PropertyDescriptor descriptor : descriptors) {
if (descriptor.getName().equals("value")) {
valueDescriptor = descriptor;
}
}
if (valueDescriptor == null) {
throw new IllegalStateException("Never thrown");
}
Method readMethod = valueDescriptor.getReadMethod();
System.out.println("READ METHOD");
System.out.println("\tReturn type: " + readMethod.getReturnType());
/*
* Since the return type is Object, I expected Superclass.class, but it
* was Subclass.class.
*/
System.out.println("\tDeclaring class: " + readMethod.getDeclaringClass());
System.out.println();
/*
* It is none of the declared methods.
*/
Method superclassMethod = Superclass.class.getMethod("getValue");
System.out.println("SUPER CLASS METHOD");
System.out.println("\tEquals read method? " + readMethod.equals(superclassMethod));
System.out.println();
Method subclassMethod = Subclass.class.getMethod("getValue");
System.out.println("SUB CLASS METHOD");
System.out.println("\tEquals read method? " + readMethod.equals(subclassMethod));
System.out.println();
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Intead of using the Introspector class, I guess I could program one myself using the Class.getMethod method. This one invoked on the subclass returns the correct method.