Java 内省 - 奇怪的行为
Java Introspection - weird behaviour
下面的代码是一个很容易重现问题的小例子。所以我有 String 类型的变量,在其上设置了默认值。我有 3 种方法:
- getter
- setter
- 将字符串转换为布尔值的便捷方法
自省不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");
}
}
有没有人对此有所了解?
附加信息:
- 顺序不会改变结果。 isTest() 方法总是被视为 readMethod
- 如果我只是将 isTest() 重命名为 bsTest(),它会选择 getter 和 setter 作为 readMethod 和 writeMethod。所以跟"is-xxx".
有关系
实际成员与 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 正在检测 isTest
和 getTest
方法。由于 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());
}
}
下面的代码是一个很容易重现问题的小例子。所以我有 String 类型的变量,在其上设置了默认值。我有 3 种方法:
- getter
- setter
- 将字符串转换为布尔值的便捷方法
自省不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");
}
}
有没有人对此有所了解?
附加信息:
- 顺序不会改变结果。 isTest() 方法总是被视为 readMethod
- 如果我只是将 isTest() 重命名为 bsTest(),它会选择 getter 和 setter 作为 readMethod 和 writeMethod。所以跟"is-xxx". 有关系
实际成员与 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>
andset<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 aget<PropertyName>
method, or it may be provided in addition to aget<PropertyName>
method.In either case, if the
is<PropertyName>
method is present for a boolean property then we will use theis<PropertyName>
method to read the property value.
根据您的示例,Introspector 正在检测 isTest
和 getTest
方法。由于 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());
}
}