1. PropertyAccessor的作用是什么
- 通过key/value的形式为对象赋值属性
- 通过字符串key访问对象属性
key:通常为字符串类型,支持嵌套属性访问和下标访问
value: 任意类型
============================================================
PropertyAccessor又分为两种
- 通过getter/setter访问属性 (BeanWrapper)
- 通过字段直接访问 (DirectFieldAccessor)
2. BeanWrapper
BeanWrapper所有的属性操作都是调用getter/setter方法完成的
如果类定义了字段,但是没有getter和setter,那么无法为这个字段赋值
有一个Student类定义如下
static class Student {
private String name;
private String firstName;
private String lastName;
private Student girlFriend;
private List<Student> friends;
public void setFirstName(String firstName) {
this.firstName = firstName;
this.name = firstName + (lastName == null ? "" : lastName);
}
public void setLastName(String lastName) {
this.lastName = lastName;
this.name = (firstName == null ? "" : firstName) + lastName;
}
public void setName(String name) {
this.name = name;
}
public void setGirlFriend(Student girlFriend) {
this.girlFriend = girlFriend;
}
public void setFriends(List<Student> friends) {
this.friends = friends;
}
public String getName() {
return name;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public Student getGirlFriend() {
return girlFriend;
}
public List<Student> getFriends() {
return friends;
}
}
使用BeanWrapper为对象赋值
@Test
public void bean_wrapper_tests() throws Exception {
// 1. 创建对象
Student lee = new Student();
// 2. 创建BeanWrapper
BeanWrapper wrapper = PropertyAccessorFactory.forBeanPropertyAccess(lee);
// 3. 赋值firstName
wrapper.setPropertyValue("firstName", "Bruce");
// 4. 验证: firstName 和 name 都有值
assertEquals("Bruce", lee.firstName);
assertEquals("Bruce", lee.name);
// 5. 赋值lastName
wrapper.setPropertyValue("lastName", "Lee");
// 6. 验证: lastName 和 name 都有值
assertEquals("Lee", lee.lastName);
assertEquals("BruceLee", lee.name);
// 7. 默认情况下, 是不允许使用嵌套属性赋值的
assertThrows(NullValueInNestedPathException.class, () -> wrapper.setPropertyValue("girlFriend.firstName", "Linda"));
// 8. 开启允许嵌套属性赋值
wrapper.setAutoGrowNestedPaths(true);
// 9. 给girlFriend赋值
wrapper.setPropertyValue("girlFriend.firstName", "Linda");
wrapper.setPropertyValue("girlFriend.lastName", "Emery");
// 10. 验证: girlFriend有值, 且girlFriend.name有值
assertNotNull(lee.girlFriend);
assertEquals("LindaEmery", lee.girlFriend.name);
// 11. 通过下标访问, 给friends:List 赋值
wrapper.setPropertyValue("friends[0].name", "Bar");
wrapper.setPropertyValue("friends[4].name", "Foo");
// 12.1 验证: frientds的长度为5
assertEquals(5, lee.friends.size());
// 12.1 验证: friends[0].name
assertEquals("Bar", lee.friends.get(0).name);
// 12.3 验证: 跳过的3个索引都有值, 但是只是一个空对象
for (int i = 1; i < 4; i++) {
assertNotNull(lee.friends.get(i));
}
// 12.4 验证: friends[4].name
assertEquals("Foo", lee.friends.get(4).name);
// 13. 嵌套属性赋值
wrapper.setPropertyValue("friends[0].friends[0].name", "Bar's friend");
// 14. 验证
assertEquals("Bar's friend", lee.getFriends().get(0).getFriends().get(0).name);
// 15. 以json的格式打印对象
Console.log(JSONUtil.toJsonStr(lee));
}
执行完后,对象的json形式如下
3. DirectFieldAccessor
DirectFieldAccessor通过直接访问字段为属性赋值
@Test
public void direct_field_tests() throws Exception {
// 1. 创建对象
Student lee = new Student();
// 2. 创建DirectFieldAccessor
ConfigurablePropertyAccessor accessor = PropertyAccessorFactory.forDirectFieldAccess(lee);
// 3. 赋值firstName
accessor.setPropertyValue("firstName", "Bruce");
// 3.1 验证: firstName有值
assertEquals("Bruce", lee.firstName);
// 3.2 验证: name为null
assertNull(lee.name);
// 4. 赋值lastName
accessor.setPropertyValue("lastName", "Lee");
// 4.1 验证: lastName有值
assertEquals("Lee", lee.lastName);
// 4.2 验证: name为null
assertNull(lee.name);
// 5. 以json的格式打印对象
Console.log(JSONUtil.toJsonStr(lee));
}
执行完后,对象的json形式如下