PropertyUtil  ## 1.copyProperties(Object, Object, String...) 将 fromObj 中的全部或者一组属性的值,复制到 toObj 对象中. **注意点:** - 如果 toObj 是null,抛出 `NullPointerException` - 如果 fromObj 是null,抛出 `NullPointerException` - 对于Date类型,不需要先注册converter - 这种copy都是 `浅拷贝`,复制后的2个Bean的同一个属性可能拥有同一个对象的ref,这个在使用时要小心,特别是对于属性为自定义类的情况 . **使用示例:** ```JAVA User oldUser = new User(); oldUser.setId(5L); oldUser.setMoney(new BigDecimal(500000)); oldUser.setDate(new Date()); oldUser.setNickName(ConvertUtil.toArray("feilong", "飞天奔月", "venusdrogon")); User newUser = new User(); PropertyUtil.copyProperties(newUser, oldUser, "date", "money", "nickName"); LOGGER.debug(JsonUtil.format(newUser)); ``` **返回: ** ```JAVA { "date": "2015-09-06 13:27:43", "id": 0, "nickName": [ "feilong", "飞天奔月", "venusdrogon" ], "age": 0, "name": "feilong", "money": 500000, "userInfo": {"age": 0} } ``` **重构:** 对于以下代码: ```JAVA private ContactCommand toContactCommand(ShippingInfoSubForm shippingInfoSubForm){ ContactCommand contactCommand = new ContactCommand(); contactCommand.setCountryId(shippingInfoSubForm.getCountryId()); contactCommand.setProvinceId(shippingInfoSubForm.getProvinceId()); contactCommand.setCityId(shippingInfoSubForm.getCityId()); contactCommand.setAreaId(shippingInfoSubForm.getAreaId()); contactCommand.setTownId(shippingInfoSubForm.getTownId()); return contactCommand; } ``` 可以重构成: ```JAVA private ContactCommand toContactCommand(ShippingInfoSubForm shippingInfoSubForm){ ContactCommand contactCommand = new ContactCommand(); PropertyUtil.copyProperties(contactCommand, shippingInfoSubForm, "countryId", "provinceId", "cityId", "areaId", "townId"); return contactCommand; } ``` 可以看出,代码更精简,目的性更明确 **BeanUtils.copyProperties(Object, Object)与 PropertyUtils.copyProperties(Object, Object)区别** - `BeanUtils` 提供类型转换功能,即发现两个JavaBean的同名属性为不同类型时,在支持的数据类型范围内进行转换,而 `PropertyUtils`不支持这个功能,但是速度会更快一些. - `commons-beanutils` v1.9.0以前的版本 `BeanUtils`不允许对象的属性值为 null,`PropertyUtils`可以拷贝属性值 null的对象. - (注:`commons-beanutils` v1.9.0+修复了这个情况,`BeanUtilsBean.copyProperties()` no longer throws a `ConversionException` for null properties of certain data types),具体参阅commons-beanutils的 RELEASE-NOTES.txt **相比较直接调用 `PropertyUtils.copyProperties(Object, Object)`的优点:** - 将 `checkedException` 异常转成了 `BeanOperationException` `RuntimeException`,因为通常copy的时候出现了`checkedException`,也是普普通通记录下log,没有更好的处理方式 - 支持 `includePropertyNames` 参数,允许针对性copy 个别属性 - 更多,更容易理解的的javadoc ## 2.describe(Object, String...) 返回一个 bean中指定属性 `propertyNames`可读属性,并将属性名/属性值放入一个 `LinkedHashMap` 中. **示例:** **场景:** 取到user bean里面所有的属性成map ```JAVA User user = new User(); user.setId(5L); user.setDate(new Date()); LOGGER.debug(JsonUtil.format(PropertyUtil.describe(user)); ``` **返回: ** ```JSON { "id": 5, "name": "feilong", "age": null, "date": "2016-07-13 22:18:26" } ``` **场景:** 提取user bean "date"和 "id"属性: ```JAVA User user = new User(); user.setId(5L); user.setDate(new Date()); LOGGER.debug(JsonUtil.format(PropertyUtil.describe(user, "date", "id")); ``` 返回的结果,按照指定参数名称顺序: ```JSON { "date": "2016-07-13 22:21:24", "id": 5 } ``` **说明:** - 另外还有一个名为class的属性,属性值是Object的类名,事实上class是`java.lang.Object`的一个属性 - 如果 `propertyNames`是null或者 empty,那么获取所有属性的值 - map的key按照 `propertyNames` 的顺序 **原理:** - 取到bean class的 `java.beans.PropertyDescriptor`数组 - 循环,找到 `java.beans.PropertyDescriptor.getReadMethod() ` - 将 name and `org.apache.commons.beanutils.PropertyUtilsBean.getProperty(Object, String)` 设置到map中 ## 3.findValueOfType(Object, Class<T>) 从指定的 obj中,查找指定类型 `toBeFindedClassType` 的值. **说明:** - 如果 `ClassUtil.isInstance(obj, toBeFindedClassType)` 直接返回 findValue - 不支持obj是`isPrimitiveOrWrapper`,`CharSequence`,`Collection`,`Map`类型,自动过滤 - 调用 `PropertyUtil.describe(Object, String)` 再递归查找 - 目前暂不支持从集合里面找到指定类型的值,如果你有相关需求,可以调用 `"org.springframework.util.CollectionUtils#findValueOfType(Collection, Class)"` **示例:** **场景:** 从User中找到UserInfo类型的值 ```JAVA User user = new User(); user.setId(5L); user.setDate(new Date()); user.getUserInfo().setAge(28); LOGGER.info(JsonUtil.format(PropertyUtil.findValueOfType(user, UserInfo.class))); ``` **返回:** ```JSON {"age": 28} ``` ## 4.getProperty(Object, String) 使用 `PropertyUtils.getProperty(Object, String)` 从指定bean对象中取得指定属性名称的值. **说明:** - 不会进行类型转换. **示例:** **场景:** 取list中第一个元素的id ```JAVA User user = new User(); user.setId(5L); user.setDate(new Date()); List<User> list = toList(user, user, user); Long id = PropertyUtil.getProperty(list, "[0].id"); ``` **返回: ** ```JSON 5 ``` ## 5.set ### 5.1 setProperty(Object, String, Object) 使用 `PropertyUtils.setProperty(Object, String, Object)` 来设置指定bean对象中的指定属性的值. **说明:** - 不会进行类型转换 **示例:** ```JAVA User newUser = new User(); PropertyUtil.setProperty(newUser, "name", "feilong"); LOGGER.info(JsonUtil.format(newUser)); ``` **返回: ** ```JSON { "age": 0, "name": "feilong" } ``` **注意点:** - 如果 bean 是null,抛出 `NullPointerException` - 如果 propertyName 是null,抛出 `NullPointerException` - 如果 propertyName 是blank,抛出 `IllegalArgumentException` - 如果bean没有传入的 propertyName属性名字,会抛出异常,see setSimpleProperty Line2078,转成 BeanOperationException - 对于Date类型,不需要先注册converter ### 5.2 setPropertyIfValueNotNull(Object, String, Object) 如果 null != value,那么才调用 `setProperty(Object, String, Object)`. **注意点:** - 如果 bean 是null,抛出 `NullPointerException` - 如果 propertyName 是null,抛出 `NullPointerException` - 如果 propertyName 是blank,抛出 `IllegalArgumentException` - 如果bean没有传入的 propertyName属性名字,会抛出异常,see `PropertyUtilsBean.setSimpleProperty(Object, String, Object)` Line2078 - 对于Date类型,不需要先注册converter ### 5.3 setPropertyIfValueNotNullOrEmpty(Object, String, Object) 如果 value isNotNullOrEmpty,那么才调用 `setProperty(Object, String, Object)`. **注意点:** - 如果 bean 是null,抛出 `NullPointerException` - 如果 propertyName 是null,抛出 `NullPointerException` - 如果 propertyName 是blank,抛出 `IllegalArgumentException` - 如果bean没有传入的 propertyName属性名字,会抛出异常,see `PropertyUtilsBean.setSimpleProperty(Object, String, Object)` Line2078 - 对于Date类型,不需要先注册converter