Java 内省 - 奇怪的行为

Java Introspection - weird behaviour

下面的代码是一个很容易重现问题的小例子。所以我有 String 类型的变量,在其上设置了默认值。我有 3 种方法:

自省不return getter 作为readMethod 和setter 作为writeMethod。相反,它 returns isTest() 方法作为 readMethod。 setter 为空。

从文档中我了解到,如果类型是布尔值,"is" 方法比 get 方法具有更高的优先级,但类型是字符串,因此甚至寻找 "is-xxx"方法?

public class Test {
    public class Arguments {
        private String test = Boolean.toString(true);

        public boolean isTest() {
            return Boolean.parseBoolean(test);
        }

        public String getTest() {
            return test;
        }

        public void setTest(String test) {
            this.test = test;
        }
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws IntrospectionException {
        BeanInfo info = Introspector.getBeanInfo(Arguments.class);
        System.out.println("Getter: " + info.getPropertyDescriptors()[1].getReadMethod());
        System.out.println("Setter: " + info.getPropertyDescriptors()[1].getWriteMethod());
        PropertyDescriptor descr = new PropertyDescriptor("test", Arguments.class);
        System.out.println("T");
    }

}

有没有人对此有所了解?

附加信息:

  1. 顺序不会改变结果。 isTest() 方法总是被视为 readMethod
  2. 如果我只是将 isTest() 重命名为 bsTest(),它会选择 getter 和 setter 作为 readMethod 和 writeMethod。所以跟"is-xxx".
  3. 有关系

实际成员与 Introspector 完全无关。例如,你可以有一个 getName() 方法,它只有 returns 一个固定的 String 并且 Introspector 会发现它是一个名为 [=18= 的成员的 getter ].如果成员不存在,您甚至可以使用 setter。您甚至可以为 Introspector 提供一个接口,它会从中确定属性,即使没有任何真正的成员也是如此。

换句话说,属性是由 getter 和 setter 方法的存在决定的,而不是由实际搜索变量决定的。

您得到的结果实际上是预期的结果,根据 JavaBeans specification

引用第 8.3.1 段的简单属性:

If we discover a matching pair of get<PropertyName> and set<PropertyName> methods that take and return the same type, then we regard these methods as defining a read-write property whose name will be <propertyName>.

然后,引用第 8.3.2 段的布尔属性:

This is<PropertyName> method may be provided instead of a get<PropertyName> method, or it may be provided in addition to a get<PropertyName> method.

In either case, if the is<PropertyName> method is present for a boolean property then we will use the is<PropertyName> method to read the property value.

根据您的示例,Introspector 正在检测 isTestgetTest 方法。由于 isTest 优先于 getTest,它使用 isTest 来确定 test 属性 的类型为 boolean。但是,Introspector 期望 setter 具有签名 void setTest(boolean test) 但它没有找到它,因此 setter 方法是 null.

需要注意的重要一点是内省器不会读取字段。它使用 getter / setter 方法的签名来确定存在哪些字段及其对应的类型。 isTest 方法签名指定类型为 boolean 的名为 test 的 属性,因此,无论 test 的实际类型如何,Introspector 都会认为您的 class 有一个 属性 boolean test.

事实上,对于Introspecter来说,属性 test可能根本不存在!您可以使用以下代码说服自己:

class Test {

    public class Arguments {
        public boolean isTest() {
            return true;
        }
    }

    public static void main(String[] args) throws IntrospectionException {
        BeanInfo info = Introspector.getBeanInfo(Arguments.class);
        System.out.println("Getter: " + info.getPropertyDescriptors()[1].getReadMethod());
        System.out.println("Name of property: " + info.getPropertyDescriptors()[1].getName());
    }

}