SpringBeaUtils 对比 ApacheBeanUtils
发布日期:2021-06-20 05:37:33 浏览次数:6 分类:技术文章

本文共 6564 字,大约阅读时间需要 21 分钟。

spring包中BeanUtils.copyProperties的实现。

spring中实现的方式很简单,就是对两个对象中相同名字的属性进行简单get/set,仅检查属性的可访问性。

private static void copyProperties(Object source, Object target, Class
editable, String... ignoreProperties) throws BeansException {
Assert.notNull(source, "Source must not be null"); Assert.notNull(target, "Target must not be null"); Class
actualEditable = target.getClass(); if (editable != null) {
if (!editable.isInstance(target)) {
throw new IllegalArgumentException("Target class [" + target.getClass().getName() + "] not assignable to Editable class [" + editable.getName() + "]"); } actualEditable = editable; } PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable); List
ignoreList = (ignoreProperties != null ? Arrays.asList(ignoreProperties) : null); //遍历各个属性 for (PropertyDescriptor targetPd : targetPds) {
Method writeMethod = targetPd.getWriteMethod(); if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {
PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName()); if (sourcePd != null) {
Method readMethod = sourcePd.getReadMethod(); if (readMethod != null && ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {
try {
//读取源值 if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
readMethod.setAccessible(true); } Object value = readMethod.invoke(source); 写入对应的属性 if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
writeMethod.setAccessible(true); } writeMethod.invoke(target, value); } catch (Throwable ex) {
throw new FatalBeanException( "Could not copy property '" + targetPd.getName() + "' from source to target", ex); } } } } } }

这种简单的方式注定了程序相比ApacheBeanUtils方法的高效性,但是会带来一些问题:null的Integer写入int类型时会报错!

User user = new User();User2 user2 = new User2();//设置空user.setId(null);//调用时会报错BeanUtils.copyProperties(user,user2);

输出结果如下:

Exception in thread "main" org.springframework.beans.FatalBeanException: Could not copy property 'id' from source to target; nested exception is java.lang.IllegalArgumentException	at org.springframework.beans.BeanUtils.copyProperties(BeanUtils.java:626)	at org.springframework.beans.BeanUtils.copyProperties(BeanUtils.java:538)	at BeanUtilsTest.main(BeanUtilsTest.java:26)Caused by: java.lang.IllegalArgumentException	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)	at java.lang.reflect.Method.invoke(Method.java:498)	at org.springframework.beans.BeanUtils.copyProperties(BeanUtils.java:622)	... 2 more

Apache commons-beanutils

commons-beanutils则施加了很多的检验,包括类型的转换,甚至于还会检验对象所属的类的可访问性。默认情况下会将Ineger、Boolean、Long等基本类型包装类为null时的值复制后转换成0或者false,有时这个可能会引起不必要的麻烦。

public void copyProperties(final Object dest, final Object orig)        throws IllegalAccessException, InvocationTargetException {
// Validate existence of the specified beans if (dest == null) {
throw new IllegalArgumentException ("No destination bean specified"); } if (orig == null) {
throw new IllegalArgumentException("No origin bean specified"); } if (log.isDebugEnabled()) {
log.debug("BeanUtils.copyProperties(" + dest + ", " + orig + ")"); } // Copy the properties, converting as necessary if (orig instanceof DynaBean) {
final DynaProperty[] origDescriptors = ((DynaBean) orig).getDynaClass().getDynaProperties(); for (DynaProperty origDescriptor : origDescriptors) {
final String name = origDescriptor.getName(); // Need to check isReadable() for WrapDynaBean // (see Jira issue# BEANUTILS-61) if (getPropertyUtils().isReadable(orig, name) && getPropertyUtils().isWriteable(dest, name)) {
final Object value = ((DynaBean) orig).get(name); copyProperty(dest, name, value); } } } else if (orig instanceof Map) {
@SuppressWarnings("unchecked") final // Map properties are always of type
Map
propMap = (Map
) orig; for (final Map.Entry
entry : propMap.entrySet()) {
final String name = entry.getKey(); if (getPropertyUtils().isWriteable(dest, name)) {
copyProperty(dest, name, entry.getValue()); } } } else /* if (orig is a standard JavaBean) */ {
final PropertyDescriptor[] origDescriptors = getPropertyUtils().getPropertyDescriptors(orig); for (PropertyDescriptor origDescriptor : origDescriptors) {
final String name = origDescriptor.getName(); if ("class".equals(name)) {
continue; // No point in trying to set an object's class } if (getPropertyUtils().isReadable(orig, name) && getPropertyUtils().isWriteable(dest, name)) {
try {
final Object value = getPropertyUtils().getSimpleProperty(orig, name); /**检查类型等操作均在此函数 *@See org.apache.commons.beanutils.BeanUtilsBean#copyProperty */ copyProperty(dest, name, value); } catch (final NoSuchMethodException e) {
// Should not happen } } } } }

而且,commons-beanutils中的装换是不支持java.util.Date的。除了支持基本类型以及基本类型的数组之外,还支持java.sql.Date, java.sql.Time, java.sql.TimeStamp, java.io.File, javaio.URL这些类的对象,其余一概不支持。不过你可以自定义你的类的Converter。然后注册进去。所以在使用时

感觉commons-beanutils包中的这个BeanUtils类的copyProperties方法,太过复杂,约束太多,而且使用不便,虽然可扩展性好了,但是易用性不高。所以在我测试的时候阿里巴巴规约插件直接提示我不要使用。。。

总结:

关于bean复制,如果属性较少,建议直接写个方法完成get/set即可。如果属性较多,可以自己采用反射实现一个满足自己需要的工具类,或者使用spring的那个beanutils类,不建议使用commons-beanutils包中的那个BeanUtils类,刚看了下,这个类对于内部静态类的对象复制也会出现问题,检验太复杂了,常会出现一些诡异的问题。毕竟我们bean复制一般就是简单的属性copy而已。

转载地址:https://blog.csdn.net/h2453532874/article/details/96768694 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:apache.commons — BeanUtils、ConvertUtils
下一篇:MySQL JSON的支持

发表评论

最新留言

哈哈,博客排版真的漂亮呢~
[***.90.31.176]2024年03月16日 10时39分17秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

python信号采集代码_13行代码实现:Python实时视频采集(附源码) 2019-04-21
h5引入json_纯js直接引入json文件 2019-04-21
python格式化字符串总结_Python字符串处理方法总结 2019-04-21
python中true什么意思_python中的bool是什么意思 2019-04-21
java list 合并 重复的数据_Java ArrayList合并并删除重复数据3种方法 2019-04-21
android volley 上传图片 和参数,android - 使用android中的volley将图像上传到multipart中的服务器 - 堆栈内存溢出... 2019-04-21
android开发的取消清空按钮,Android开发实现带清空按钮的EditText示例 2019-04-21
android gp服务,ArcGIS Runtime SDK for Android开发之调用GP服务(异步调用) 2019-04-21
mysql整体会滚_滚mysql 2019-04-21
向mysql数据库中添加批量数据类型_使用JDBC在MySQL数据库中快速批量插入数据 2019-04-21
最全的mysql 5.7.13_最全的mysql 5.7.13 安装配置方法图文教程(linux) 强烈推荐! 2019-04-21
mssql连接mysql数据库文件_在本地 怎么远程连接MSSQL数据库 2019-04-21
mssql 远程无法连接mysql_解决SQLServer远程连接失败的问题 2019-04-21
linux mysql c++编程_Linux下进行MYSQL的C++编程起步手记 2019-04-21
Maria数据库怎么复制到mysql_MySQL、MariaDB数据库的AB复制配置过程 2019-04-21
mysql5.6 icp mrr bak_【mysql】关于ICP、MRR、BKA等特性 2019-04-21
mysql utf8跟utf8mb4_MySQL utf8 和 utf8mb4 的区别 2019-04-21
docker mysql开机自启动_Docker学习4-学会如何让容器开机自启服务【坑】 2019-04-21
在mysql中删除表正确的是什么_在MySQL中删除表的操作教程 2019-04-21
mysql有3个共同好友_共同好友mysql 2019-04-21