简体   繁体   English

Java 8接口默认方法似乎没有声明属性

[英]Java 8 interface default method doesn't seem to declare property

In my application I run into a problem that when a getter in a class is defaulted in an interface only (Java 8 feature), there is no Java Beans property as a result. 在我的应用程序中,我遇到一个问题,当类中的getter仅在接口中默认(Java 8特性)时,结果没有Java Beans属性。 Ie for normal method invocation it works just as a standard method, but for access through "properties" it suddenly behaves differently... 即正常方法调用它只是作为一种标准方法,但对于通过“属性”访问它突然表现不同......

Here is a test case: 这是一个测试用例:

import java.beans.Introspector;
import java.util.Arrays;
import java.util.stream.Collectors;
import org.apache.commons.beanutils.PropertyUtils;

public class test
{
    public static void main (String[] arguments) throws Exception
    {
        // Normal language-level invocation, works fine.
        System.out.println (new Bean1 ().getFoo ());
        System.out.println (new Bean2 ().getFoo ());

        // Printing Java Beans properties; Bean2 doesn't have 'foo' property...
        System.out.println (Arrays.stream (Introspector.getBeanInfo (Bean1.class).getPropertyDescriptors ())
                            .map ((property) -> property.getName ())
                            .collect (Collectors.joining (", ")));
        System.out.println (Arrays.stream (Introspector.getBeanInfo (Bean2.class).getPropertyDescriptors ())
                            .map ((property) -> property.getName ())
                            .collect (Collectors.joining (", ")));

        // First call behaves as expected, second dies with exception.
        System.out.println (PropertyUtils.getProperty (new Bean1 (), "foo"));
        System.out.println (PropertyUtils.getProperty (new Bean2 (), "foo"));
    }

    public interface Foo
    {
        default String getFoo ()
        {
            return "default foo";
        }
    }

    public static class Bean1 implements Foo
    {
        @Override
        public String getFoo ()
        {
            return "special foo";
        }
    }

    public static class Bean2 implements Foo
    { }
}

Result: 结果:

special foo
default foo
class, foo
class
special foo
Exception in thread "main" java.lang.NoSuchMethodException: Unknown property 'foo' on class 'class test$Bean2'
        at org.apache.commons.beanutils.PropertyUtilsBean.getSimpleProperty(PropertyUtilsBean.java:1257)
        at org.apache.commons.beanutils.PropertyUtilsBean.getNestedProperty(PropertyUtilsBean.java:808)
        at org.apache.commons.beanutils.PropertyUtilsBean.getProperty(PropertyUtilsBean.java:884)
        at org.apache.commons.beanutils.PropertyUtils.getProperty(PropertyUtils.java:464)
        at test.main(test.java:21)

Questions: do I do something wrong or is it a bug in Java? 问题:我做错了什么或者它是Java中的错误? Is there a workaround other than never using defaulted methods (for getters/setters) in case you might need to access them as a "property" at some point later? 除了从不使用默认方法(针对getter / setter)之外,还有一种解决方法,以防您以后需要在某个时候访问它们作为“属性”吗?

I always hated Java "properties by convention" that tend to break because you sneeze the wrong way. 我总是讨厌Java“按惯例的属性”,因为你打喷嚏的方式不对。

This seems to be indeed an erroneous omission in the Beans Introspector . 这似乎确实是Beans Introspector中的一个错误遗漏。 Here is a workaround other than not using default methods: 除了不使用default方法之外,还有一个解决方法:

public static void main (String[] arguments) throws Exception {
    testBean(new Bean1());
    System.out.println();
    testBean(new Bean2());
}
static void testBean(Object bean) throws Exception {
    PropertyDescriptor[] pd
        = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
    System.out.println(Arrays.stream(pd)
        .map(PropertyDescriptor::getName).collect(Collectors.joining(", ")));
    for(PropertyDescriptor p: pd)
        System.out.println(p.getDisplayName()+": "+p.getReadMethod().invoke(bean));
}
public interface Foo {
    default String getFoo() {
        return "default foo";
    }
}
public static class Bean1 implements Foo {
    @Override
    public String getFoo() {
        return "special foo";
    }
}
public static class Bean2BeanInfo extends SimpleBeanInfo {
    private final BeanInfo ifBeanInfo;
    public Bean2BeanInfo() throws IntrospectionException {
        ifBeanInfo=Introspector.getBeanInfo(Foo.class);
    }
    @Override
    public BeanInfo[] getAdditionalBeanInfo() {
        return new BeanInfo[]{ifBeanInfo};
    }
}
public static class Bean2 implements Foo { }
class, foo
class: class helper.PropTest$Bean1
foo: special foo
class, foo
class: class helper.PropTest$Bean2
foo: default foo

A quick work-around: 快速解决方法:

try {
    return PropertyUtils.getProperty(bean, property);
}
catch (NoSuchMethodException e) {
    String getMethod = "get" + property.substring(0, 1).toUpperCase() + property.substring(1);
    return MethodUtils.invokeMethod(bean, getMethod, new Object[]{});
}

I don't know if my answer will be helpful, but I solved similar problem by using BeanUtils.getPropertyDescriptors(clazz) from Spring. 我不知道我的答案是否有用,但我通过使用Spring的BeanUtils.getPropertyDescriptors(clazz)解决了类似的问题。 It understands default methods. 它了解默认方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM