Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/374.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 8接口默认方法不';我似乎没有申报财产_Java_Java 8_Javabeans_Default Method - Fatal编程技术网

Java 8接口默认方法不';我似乎没有申报财产

Java 8接口默认方法不';我似乎没有申报财产,java,java-8,javabeans,default-method,Java,Java 8,Javabeans,Default Method,在我的应用程序中,我遇到了这样一个问题:当类中的getter仅在接口(Java8特性)中被默认时,结果就没有JavaBeans属性。也就是说,对于正常的方法调用,它就像一个标准方法一样工作,但是对于通过“属性”进行的访问,它突然表现出不同的行为 下面是一个测试用例: import java.beans.Introspector; import java.util.Arrays; import java.util.stream.Collectors; import org.apache.commo

在我的应用程序中,我遇到了这样一个问题:当类中的getter仅在接口(Java8特性)中被默认时,结果就没有JavaBeans属性。也就是说,对于正常的方法调用,它就像一个标准方法一样工作,但是对于通过“属性”进行的访问,它突然表现出不同的行为

下面是一个测试用例:

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
    { }
}
结果:

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)
问题:我是做错了什么,还是Java中的错误?如果您以后可能需要将它们作为“属性”访问,除了从不使用默认方法(对于getter/setter)之外,还有其他解决方法吗


我一直很讨厌Java“按约定的属性”,因为你打喷嚏的方式不对,所以它很容易崩溃。

这似乎确实是Beans
Interspector中的一个错误遗漏。除了不使用
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 { }
类,foo
类:类helper.PropTest$Bean1
特别食物
上课,富
类:类helper.PropTest$Bean2
foo:默认的foo
快速解决方法:

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[]{});
}

我不知道我的答案是否有用,但我使用Spring中的
BeanUtils.getPropertyDescriptors(clazz)
解决了类似的问题。它理解默认方法

坦白地说,这比一开始就不使用默认方法更不方便。嗯,你说过你讨厌“按约定的属性”,那么显式beaninfo有什么问题呢?但无论如何,Java8允许您使用单行程序创建基于函数的属性类对象,因此我也不认为基于反射的工具有什么意义。尽管如此,唯一的替代方法是等待Oracle解决这个问题……霍尔格:我想要显式属性,但如果Java对它们有一个合理的语法,就不要在现有机制的基础上进行黑客攻击。你的方法的一个大问题是所有东西都分布在不同的地方,所以你在一个地方有getter/setter,在其他地方有bean信息等等。我看不出有什么东西分布在不同的地方。
Bean2BeanInfo
就在它描述的
Bean2
类中,它所说的是
Bean2
应该包含
Foo
的信息,同样的
Bean2实现Foo
在它下面说了七行。bean类和bean信息类在一个位置形成一对。
default
方法位于其他地方是
default
方法的一个属性。“基于函数的属性,如对象”意味着有类似于
类属性{String name;function getter;BiConsumer setter;}
的内容,加上它的常用内容、工厂方法等,具体取决于用例,它甚至不需要有名字。然后,可以像
readOnly(Bean1::getFoo)
那样声明一个属性,假设使用了适当的工厂方法,那么您将得到一个
属性。如前所述,声明一个类的所有属性可以变成一行,生成一个属性数组或一个
映射
,等等……看起来这已经被JDK版本所涵盖,但尚未在任何JDK版本中得到修复。是的,的确如此。希望他们能治好。我也被这个虫子咬了。OpenJDK bug计划用于Java 9,这意味着我们必须至少等到2016年9月才能修复。同时,我只需在需要属性的类中创建一个委托方法。@Hennovermelen:是的,问题是我经常使用属性,因为我与EL和脚本语言交互。这个bug基本上让我对默认方法保持警惕,因为属性(Java中的编译器没有检查)可能会在没有通知的情况下中断。将一些标准实现移动到默认接口方法尤其令人恼火:这种看似安全的操作可能会把事情搞砸,而且事先没有好的方法告诉您。@StuartMarks:有没有可能碰到JDK bug?我的代码充斥着
@Override public Foo getFoo(){return MyInterface.super.getFoo();}
,这是因为它……在我的情况下,它没有帮助,因为我需要属性从Java EL可见。也就是说,我不控制访问它们的位置。我认为这是错误的。我假设您使用的是Apache的库,其中包含一个方法PropertyUtils.getPropertyDescriptors(类)。这个方法使用的java.beans.Introspector与所讨论的()相同。正如我所说的,我的解决方案使用的是Spring而不是Apache Commons的解决方案。这不是我自己访问属性,而是让我无法控制的代码(EL脚本实现)看到有一个属性。