FULL PRODUCT VERSION :
java version "1.8.0"
Java(TM) SE Runtime Environment (build 1.8.0-b132)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b70, mixed mode)
A DESCRIPTION OF THE PROBLEM :
java.beans.Introspector.getBeanInfo() throws a NullPointerException if you have a pair of getTer()/setTer() methods in a base class; and a pair of getTer()/setTer() methods in a subclass (or auto-generated proxy); and getTer() return type is not exactly the same as setTer() argument type (in my case, getTer() returns Set and setTer() only accepts some Set sub-interface).
We caught that by using Introspector on javassist Proxies returned by Hibernate. We have our own set implementation but Hibernate demands the use of the java.util.Set, hence the mixed use of both that led to the discovery of this bug.
See the code sample.
REGRESSION. Last worked in version 7u45
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
See the code sample.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Bean info is returned.
ACTUAL -
NullPointerException is being thrown.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread "main" java.lang.NullPointerException
at java.lang.Class.isAssignableFrom(Native Method)
at java.beans.Introspector.isAssignable(Introspector.java:809)
at java.beans.Introspector.processPropertyDescriptors(Introspector.java:705)
at java.beans.Introspector.getTargetPropertyInfo(Introspector.java:553)
at java.beans.Introspector.getBeanInfo(Introspector.java:428)
at java.beans.Introspector.getBeanInfo(Introspector.java:262)
at IntrospectorFail.main(IntrospectorFail.java:39)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.beans.Introspector;
import java.util.Set;
public class IntrospectorFail {
public interface SetF<X> extends Set<X> { }
public class Base {
private SetF<Object> items;
public Set<Object> getItems() {
return items;
}
public void setItems(SetF<Object> items) {
this.items = items;
}
}
public class Child extends Base {
public Set<Object> getItems() {
return super.getItems();
}
public void setItems(SetF<Object> items) {
super.setItems(items);
}
}
public static void main(String[] args) throws Throwable {
// OK
Introspector.getBeanInfo(Base.class, Object.class, Introspector.USE_ALL_BEANINFO);
// OK
Introspector.getBeanInfo(Child.class, Base.class, Introspector.USE_ALL_BEANINFO);
// BOOM
Introspector.getBeanInfo(Child.class, Object.class, Introspector.USE_ALL_BEANINFO);
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
- Make sure getters' and setter' parameter/return class is exactly the same.
- Use stopClass = getSuperclass() (not applicable if error manifests inside a library)