I have a little problem with default methods in Interface and BeanInfo Introspector. In this example, there is interface: Interface
public static interface Interface {
default public String getLetter() {
return "A";
}
}
and two classes ClassA and ClassB:
public static class ClassA implements Interface {
}
public static class ClassB implements Interface {
public String getLetter() {
return "B";
}
}
In main method app prints PropertyDescriptors from BeanInfo:
public static String formatData(PropertyDescriptor[] pds) {
return Arrays.asList(pds).stream()
.map((pd) -> pd.getName()).collect(Collectors.joining(", "));
}
public static void main(String[] args) {
try {
System.out.println(
formatData(Introspector.getBeanInfo(ClassA.class)
.getPropertyDescriptors()));
System.out.println(
formatData(Introspector.getBeanInfo(ClassB.class)
.getPropertyDescriptors()));
} catch (IntrospectionException e) {
e.printStackTrace();
}
}
And the result is:
class
class, letter
Why default method "letter" is not visible as property in ClassA? Is it bug or feature?
We noticed the same problem, particularly with Java EL and JPA. This is likely to affect multiple frameworks that use Introspector to discover properties that follow the JavaBean convention.
There is an official Bug opened. I thought I would add this for reference since it is creating problems for multiple frameworks.
The official Fix version is 21. I asked if it could possibly be backported to 17.
More Info for EL specific issues: https://github.com/jakartaee/expression-language/issues/43
There may be at least a partial fix in Jakarta EE 10.
However, there is a fully working workaround for EE < 10 and JDK < 21. You can simply make a BeanInfo
class that describes the properties inherited from the interface. Here, MyClass
is inheriting aProperty
getter/setters from an interface. To expose these to the JDK Introspector, simply create a BeanInfo
class:
public class MyClassBeanInfo extends SimpleBeanInfo {
@Override
public BeanInfo[] getAdditionalBeanInfo() {
return new BeanInfo[] { new SimpleBeanInfo() {
@Override
public PropertyDescriptor[] getPropertyDescriptors() {
try {
return new PropertyDescriptor[] { new PropertyDescriptor("aProperty", MyClass.class, "getAProperty", "setAProperty") };
} catch (final IntrospectionException e) {
throw new RuntimeException(e);
}
}
} };
}
}
Reference: https://docs.oracle.com/javase/8/docs/api/java/beans/BeanInfo.html