Java 8和Bean Info Introspector中接口的默认方法

ptr*_*trr 13 java interface javabeans propertydescriptor java-8

我对Interface和BeanInfo Introspector中的默认方法有一点问题.在这个例子中,有接口:Interface

public static interface Interface {
    default public String getLetter() {
        return "A";
    }
}
Run Code Online (Sandbox Code Playgroud)

以及ClassA和ClassB两个类:

public static class ClassA implements Interface {
}

public static class ClassB implements Interface {
    public String getLetter() {
        return "B";
    }
}
Run Code Online (Sandbox Code Playgroud)

在main方法应用程序中打印来自BeanInfo的PropertyDescriptors:

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();
    }

}
Run Code Online (Sandbox Code Playgroud)

结果是:

class
class, letter
Run Code Online (Sandbox Code Playgroud)

为什么默认方法"letter"在ClassA中不可见为属性?是bug还是功能?

Iva*_*sov 7

我猜想,即使使用 Java 8 虚拟扩展方法(又名防御者,默认方法)接口可以有一些看起来像属性方法的东西,也Introspector不会处理层次结构链。interface这是一个相当简单的内省器,声称它确实如此:BeanIntrospector

这是否可以被视为一个错误在某种程度上是一个灰色地带,这就是我这么认为的原因。

显然,现在一个类可以从接口“继承”一个方法,该方法具有官方认为的 getter/setter/mutator 的所有品质。但与此同时,这整件事违背了接口的目的——接口不可能提供任何可以被视为属性的东西,因为它是无状态和无行为的,它只是为了描述行为。即使防御者方法基本上也是静态的,除非它们访问具体实现的真实属性。

另一方面,如果我们假设防御者是正式继承的(而不是提供默认实现,这是一个相当模糊的定义),它们应该导致在实现类中创建合成方法,并且这些方法属于该类并被遍历为查找的一部分PropertyDescriptor显然,事实并非如此,否则整个事情都会正常进行。:)看来防御者方法在这里得到了某种特殊待遇。


Jon*_*her 2

我们注意到同样的问题,特别是 Java EL 和 JPA。这可能会影响使用 Introspector 来发现遵循 JavaBean 约定的属性的多个框架。

官方有一个Bug被打开。我想我应该添加这个作为参考,因为它给多个框架带来了问题。

官方的 Fix 版本是 21。我问是否可以向后移植到 17。

编辑

有关 EL 特定问题的更多信息:https ://github.com/jakartaee/expression-language/issues/43

Jakarta EE 10 中可能至少有部分修复。

然而,对于 EE < 10 和 JDK < 21 有一个完全可行的解决方法。您可以简单地创建一个BeanInfo类来描述从接口继承的属性。这里,是从接口MyClass继承getter/setter。aProperty要将这些公开给 JDK Introspector,只需创建一个BeanInfo类:

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);
                }
            }
        } };
    }
}
Run Code Online (Sandbox Code Playgroud)

参考:https ://docs.oracle.com/javase/8/docs/api/java/beans/BeanInfo.html