Java 8和Bean信息内省器中接口中的默认方法
我对Interface和BeanInfo Introspector中的默认方法有点问题。 在这个例子中,有一个接口:interfaceJava 8和Bean信息内省器中接口中的默认方法,java,interface,javabeans,java-8,propertydescriptor,Java,Interface,Javabeans,Java 8,Propertydescriptor,我对Interface和BeanInfo Introspector中的默认方法有点问题。 在这个例子中,有一个接口:interface public static interface Interface { default public String getLetter() { return "A"; } } 以及两个类别A和类别B: public static class ClassA implements Interface { } public stat
public static interface Interface {
default public String getLetter() {
return "A";
}
}
以及两个类别A和类别B:
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中不作为属性可见?这是bug还是特性?这是因为您只在接口和类B上使用方法,而不是直接在类A上使用方法。然而,对我来说,这听起来像一个bug,因为我希望该属性会出现在列表中。我怀疑InProSector还没有赶上Java 8的功能。调试显示,该方法在
内省程序#getPublicDeclaredMethods()中被过滤掉了。
:
其中,clz
是所讨论类的完全限定名
由于
ClassB
有此方法的自定义实现,因此它成功地通过了检查,而ClassA
没有。我想,Introspector
不会处理接口
层次结构链,即使使用Java 8虚拟扩展方法(也称为defenders,默认方法)接口可以有一些类似于属性方法的东西。这里有一个相当简单的内省者声称它确实做到了:
这是否可以被认为是一个bug是一个灰色地带,以下是我这么认为的原因
显然,现在一个类可以从一个接口“继承”一个方法,该方法具有通常被认为是getter/setter/mutator的所有特性。但同时,这一切都违背了接口的目的——接口不可能提供任何可以被视为属性的东西,因为它是无状态和无行为的,它只是用来描述行为的。即使defender方法也基本上是静态的,除非它们访问具体实现的真实属性
另一方面,如果我们假设捍卫者是正式继承的(而不是提供默认实现,这在某种程度上是一个不明确的定义),那么它们应该导致在实现类中创建合成方法,这些方法属于该类,并且作为
PropertyDescriptor
查找的一部分进行遍历。很明显,事情不是这样的,否则整个事情都会起作用似乎defender方法在这里得到了某种特殊处理。我认为这也是一个bug。
您可以为您的类使用专用的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;
}
/*(非Javadoc)
*@see java.beans.SimpleBeanInfo#getAdditionalBeanInfo()
*/
@凌驾
公共BeanInfo[]获取附加BeanInfo()
{
Class superclass=Interface.Class;
BeanInfo info=null;
尝试
{
info=Introspector.getBeanInfo(超类);
}
捕获(内省异常e)
{
//无事可做
}
如果(信息!=null)
返回新的BeanInfo[]{info};
返回null;
}
继承的方法如何?“这些不会也被过滤掉吗?”@SotiriosDelimanolis是的,它也被过滤掉了。但是在processPropertyDescriptors()
方法的范围内,几乎有200行长,它被添加回:)我删除了我的答案,因为它是一个大脑屁。我的2美分是一只虫子。如果ClassC扩展了ClassB,并且没有提供代码,它将显示类,字母
。因此,这不是一个只报告直接类的情况。
/* (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;
}