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

时间:2014-04-22 12:05:03

标签: java interface javabeans java-8 propertydescriptor

我对Interface和BeanInfo Introspector中的默认方法有一点问题。 在此示例中,有interface:Interface

public static interface Interface {
    default public String getLetter() {
        return "A";
    }
}

和两个类ClassA和ClassB:

public static class ClassA implements Interface {
}

public static class ClassB implements Interface {
    public String getLetter() {
        return "B";
    }
}

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

}

结果是:

class
class, letter

为什么选择默认方法"字母"在ClassA中不可见作为属性?是错误还是功能?

4 个答案:

答案 0 :(得分:4)

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

这是否可以被认为是一个灰色区域,这就是为什么我这么认为。

显然,现在一个类可以从一个接口“继承”一个方法,该方法具有通常被认为是getter / setter / mutator的所有特性。但与此同时,这一切都违背了接口的目的 - 接口不可能提供任何可被视为属性的东西,因为它是无状态且无行为的,它只是意味着描述行为。即使是defender方法也基本上是静态的,除非它们访问具体实现的真实属性。

另一方面,如果我们假设防御者正式继承(而不是提供默认实现,这在某种程度上是一个不明确的定义),他们应该导致合成在实现类中创建的方法,以及属于该类的方法,并作为PropertyDescriptor查找的一部分进行遍历。 显然这不是它的方式,否则整个事情都会起作用。 :)似乎防守方法在这里得到某种特殊待遇。

答案 1 :(得分:1)

我认为这也是一个错误。 你可以使用专门的BeanInfo为你的类解决这个问题,并提供类似的东西:

/* (non-Javadoc)
 * @see java.beans.SimpleBeanInfo#getAdditionalBeanInfo()
 */
@Override
public BeanInfo[] getAdditionalBeanInfo()
{
    Class<?> superclass = Interface.class;
    BeanInfo info = null;

    try
    {
        info = Introspector.getBeanInfo(superclass);
    }
    catch (IntrospectionException e)
    {
        //nothing to do
    }

    if (info != null)
        return new BeanInfo[] { info };

    return null;
}

答案 2 :(得分:0)

这是因为您只在Interface和ClassB上使用您的方法,而不是直接在ClassA上。然而,这听起来像是一个bug,因为我希望该属性能够在列表中显示出来。我怀疑Inrospector还没有赶上Java 8的功能。

答案 3 :(得分:0)

调试显示此方法已在Introspector#getPublicDeclaredMethods()过滤掉:

if (!method.getDeclaringClass().equals(clz)) {
    result[i] = null; // ignore methods declared elsewhere
}

其中clz是相关类的完全限定名称。

由于ClassB具有此方法的自定义实现,因此它会在ClassA没有成功通过检查。