【问题标题】:Java Introspection - weird behaviourJava Introspection - 奇怪的行为
【发布时间】:2015-12-04 14:14:28
【问题描述】:

下面的代码是一个可以轻松重现问题的小示例。所以我有一个字符串类型的变量,在它上面设置了一个默认值。我有 3 种方法:

  • 吸气剂
  • 二传手
  • 将字符串转换为布尔值的便捷方法

自省不会将 getter 作为 readMethod 并将 setter 作为 writeMethod 返回。相反,它返回 isTest() 方法作为 readMethod。设置器为空。

从文档中我了解到,如果类型是布尔值,则“is”方法的优先级高于 get,但类型是 String,因此即使查找“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”有关。

【问题讨论】:

  • 如果在类的末尾声明isTest 方法会发生什么?它可能被识别为布尔值,因为这是第一次出现,因此 setter 与 String 类型不匹配。
  • 不,这没有意义,但显然这是他们决定的(或者这是一个错误)。你对此无能为力,除了停下来用字符串表示布尔值:D
  • 我在初始文本中添加了更多信息。顺序对结果没有影响。

标签: java javabeans introspection


【解决方案1】:

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

引用第 8.3.1 段的简单属性:

如果我们发现一对匹配的 get<PropertyName>set<PropertyName> 方法 接受和返回相同的类型,那么我们认为这些方法定义了一个读写属性,其名称将是<propertyName>

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

可以提供此is<PropertyName> 方法来代替get<PropertyName> 方法,也可以在get<PropertyName> 方法之外提供它。

在任何一种情况下,如果布尔属性存在is<PropertyName> 方法,那么我们将使用is<PropertyName> 方法来读取属性值。

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

需要注意的重要一点是 Introspector 不会读取字段。它使用 getter / setter 方法的签名来确定存在哪些字段及其对应的类型。 isTest 方法签名为boolean 类型的名为test 的属性指定,因此,无论test 的实际类型如何,Introspector 都会认为您的类具有属性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());
    }

}

【讨论】:

  • 我同意 Tunaki 的观点,如果你正在做一些元编程,你可以通过一些参数强制它按照你的意愿工作:PropertyDescriptor descr = new PropertyDescriptor("test", Arguments.class, "getTest", "setTest");
  • 您提到“它使用isTest来确定测试属性的类型为布尔值”,但测试的类型明确定义为String。还是因为方法的返回值是布尔值而将类型定义为布尔值?
  • @Quirexx Introspector 不读取这些字段。它使用 getter / setter 方法的签名来确定存在哪些字段及其对应的类型。 isTest 签名为布尔类型的名为“test”的属性指定,而不管“test”的实际类型如何
  • 所以它只查看方法并遵循 JavaBeans 命名约定来确定属性。如果你这样看,结果确实是正确的。现在它是有道理的。谢谢!
【解决方案2】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-06
    • 2018-08-15
    • 2017-09-27
    • 2012-02-16
    • 2021-09-28
    • 2023-03-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多