FULL PRODUCT VERSION :
java version "1.7.0_45"
Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.1.7601]
A DESCRIPTION OF THE PROBLEM :
Introspector.getBeanInfo throws AssertionError(cause: java.beans.IntrospectionException) when trying to get BeanInfo for a class that specializes return type of indexed getter method in sub-class.
I would expect that indexed and non-indexed properties should be handled by Introspector using similar logic.
In the attached example BeanInfo is generated for class with single non-indexed property,
but fails with AssertionError if we modify the property to be indexed.
I have found similar bug report with a fix for java.beans.PropertyDescriptor:
http://hg.openjdk.java.net/jdk7u/jdk7u-dev/jdk/rev/ef26b6c8264d
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run example code
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
All assertions should pass
ACTUAL -
AssertionError is thrown from IndexedPropertyDescriptor line 480
ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread "main" java.lang.AssertionError: java.beans.IntrospectionException: type mismatch between indexed read and indexed write methods: value
at java.beans.IndexedPropertyDescriptor.<init>(IndexedPropertyDescriptor.java:480)
at java.beans.Introspector.processPropertyDescriptors(Introspector.java:647)
at java.beans.Introspector.getTargetPropertyInfo(Introspector.java:543)
at java.beans.Introspector.getBeanInfo(Introspector.java:418)
at java.beans.Introspector.getBeanInfo(Introspector.java:163)
at com.pivotcapital.test.IntrospectorIssue.main(IntrospectorIssue.java:10)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: java.beans.IntrospectionException: type mismatch between indexed read and indexed write methods: value
at java.beans.IndexedPropertyDescriptor.findIndexedPropertyType(IndexedPropertyDescriptor.java:387)
at java.beans.IndexedPropertyDescriptor.setIndexedReadMethod(IndexedPropertyDescriptor.java:215)
at java.beans.IndexedPropertyDescriptor.<init>(IndexedPropertyDescriptor.java:471)
... 10 more
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.beans.*;
public class IntrospectorIssue {
public static void main(String[] args) {
// Getting BeanInfo for class with non-indexed property
try {
final BeanInfo beanInfo = Introspector.getBeanInfo(TestClass1.class);
final PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
assert descriptors.length == 2;
final PropertyDescriptor classPropertyDescriptor = descriptors[0];
assert "class".equals(classPropertyDescriptor.getName());
final PropertyDescriptor valuePropertyDescriptor = descriptors[1];
assert "value".equals(valuePropertyDescriptor.getName());
assert Number.class.equals(valuePropertyDescriptor.getPropertyType());
} catch (Throwable e) {
e.printStackTrace();
}
// Getting BeanInfo for class with indexed property
try {
final BeanInfo beanInfo = Introspector.getBeanInfo(TestClass2.class);
final PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
assert descriptors.length == 2;
final PropertyDescriptor classPropertyDescriptor = descriptors[0];
assert "class".equals(classPropertyDescriptor.getName());
final PropertyDescriptor valuePropertyDescriptor = descriptors[1];
assert "value".equals(valuePropertyDescriptor.getName());
assert Number.class.equals(valuePropertyDescriptor.getPropertyType());
} catch (Throwable e) {
e.printStackTrace();
}
}
public static abstract class AbstractTestClass1 {
public Number getValue() {
return null;
}
public void setValue(Number value) {
}
}
public static class TestClass1 extends AbstractTestClass1 {
public Long getValue() {
return null;
}
public void setValue(Number value) {
}
}
public static abstract class AbstractTestClass2 {
public Number getValue(int i) {
return null;
}
public void setValue(int i, Number value) {
}
}
public static class TestClass2 extends AbstractTestClass2 {
public Long getValue(int i) {
return null;
}
public void setValue(int i, Number value) {
}
}
}
---------- END SOURCE ----------