Java 8和Bean Info Introspector中接口的默认方法
我对Interface和BeanInfo Introspector中的默认方法有一点问题。 在这个例子中,有接口: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
为什么默认方法“letter”在ClassA中不可见为属性? 是bug还是function?
我猜, Introspector
不会处理interface
层次结构链,即使使用Java 8虚拟扩展方法(也称为防御者,默认方法)接口可以使某些东西看起来像属性方法。 这是一个相当简单的内省探测器声称它: BeanIntrospector
这是否可以被认为是一个灰色区域,这就是为什么我这么认为。
显然,现在一个类可以从一个接口“inheritance”一个方法,该方法具有通常被认为是getter / setter / mutator的所有特性。 但与此同时,这一切都违背了接口的目的 – 接口不可能提供任何可被视为属性的东西,因为它是无状态且无行为的,它只是用来描述行为。 甚至防御方法基本上都是静态的,除非它们访问具体实现的真实属性。
另一方面,如果我们假设防御者是正式inheritance的 (而不是提供默认实现 ,这在某种程度上是一个不明确的定义),它们应该导致在实现类中创建合成方法,并且那些属于类并且遍历作为PropertyDescriptor
查找的一部分。 显然这不是它的方式,否则整个事情都会起作用。 🙂似乎防守方法在这里得到某种特殊待遇。
我认为这也是一个错误。 你可以使用专门的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; }
这是因为您只在Interface和ClassB上使用您的方法,而不是直接在ClassA上。 然而,这听起来像是一个bug,因为我希望该属性能够在列表中显示出来。 我怀疑Inrospector还没有赶上Java 8的function。
调试显示此方法在Introspector#getPublicDeclaredMethods()
被过滤掉:
if (!method.getDeclaringClass().equals(clz)) { result[i] = null; // ignore methods declared elsewhere }
其中clz
是相关类的完全限定名称。
由于ClassB
具有此方法的自定义实现,因此它成功通过了检查,而ClassA
则没有。