点击关注下方公众号,架构师全套资料 都在这里

0、2T架构师学习资料干货分享

上一篇:百度前员工因内网发布“女优一览表”被辞退,自诉原因:想转岗鉴黄师!!!

大家好,我是互联网架构师。

1. 背景

之前在专栏中讲过“不推荐使用属性拷贝工具”,推荐直接定义转换类和方法使用 IDEA 插件自动填充 get / set 函数。

不推荐的主要理由是:

  • 有些属性拷贝工具性能有点差

  • 有些属性拷贝工具有“BUG”

  • 使用属性拷贝工具容易存在一些隐患(后面例子会讲到)

2. 示例

首先公司内部就遇到过 commons 包的 BeanUtils 进行属性拷贝性能较差的真实案例,然后该同事换成了 Spring 的 BeanUtils 性能好了很多,感兴趣大家可以使用性能测试框架或者基准测试框架去对比,这里就不对比了。

接下来我们看 Spring 的 BeanUtils 的属性拷贝会存在啥问题:

import lombok.Data;import java.util.List;@Data
public class A {private String name;private List<Integer> ids;
}
@Data
public class B {private String name;private List<String> ids;
}
import org.springframework.beans.BeanUtils;import java.util.Arrays;public class BeanUtilDemo {public static void main(String[] args) {A first = new A();first.setName("demo");first.setIds(Arrays.asList(1, 2, 3));B second = new B();BeanUtils.copyProperties(first, second);for (String each : second.getIds()) {// 类型转换异常System.out.println(each);}}
}

大家运行上述示例时,会发生类型转换异常。

打断点可以看到,属性拷贝之后 B 类型的 second 对象中 ids 仍然为 Integer 类型:

如果不转换为字符串,直接进行打印,并不会报错。


使用CGlib 在不定义Converter 的情况下也会遇到类似问题:

import org.easymock.cglib.beans.BeanCopier;import java.util.Arrays;public class BeanUtilDemo {public static void main(String[] args) {A first = new A();first.setName("demo");first.setIds(Arrays.asList(1, 2, 3));B second = new B();final BeanCopier beanCopier = BeanCopier.create(A.class, B.class, false);beanCopier.copy(first,second,null);for (String each : second.getIds()) {// 类型转换异常System.out.println(each);}}
}

同样,问题在运行时才暴露出来。


接下来我们看下 mapstruct:

import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;@Mapper
public interface Converter {Converter INSTANCE = Mappers.getMapper(Converter.class);B aToB(A car);
}
import java.util.Arrays;public class BeanUtilDemo {public static void main(String[] args) {A first = new A();first.setName("demo");first.setIds(Arrays.asList(1, 2, 3));B second = Converter.INSTANCE.aToB(first);for (String each : second.getIds()) {// 正常System.out.println(each);}}
}

可以成功的将 A 中 List<Integer> 转为 B 中的 List<String> 类型。

我们看下编译生成的 Converter 实现类:

import java.util.ArrayList;
import java.util.List;
import javax.annotation.Generated;
import org.springframework.stereotype.Component;@Generated(value = "org.mapstruct.ap.MappingProcessor",comments = "version: 1.3.1.Final, compiler: javac, environment: Java 1.8.0_202 (Oracle Corporation)"
)
@Component
public class ConverterImpl implements Converter {@Overridepublic B aToB(A car) {if ( car == null ) {return null;}B b = new B();b.setName( car.getName() );b.setIds( integerListToStringList( car.getIds() ) );return b;}protected List<String> integerListToStringList(List<Integer> list) {if ( list == null ) {return null;}List<String> list1 = new ArrayList<String>( list.size() );for ( Integer integer : list ) {list1.add( String.valueOf( integer ) );}return list1;}
}

自动帮我们进行了转换,我们可能没有意识到类型并不一致。

如果我们在 A 类中添加一个 String number 属性,在 B 类中添加一个 Long number 属性,使用 mapstruect 当 number 设置为非数字类型时就会报 .NumberFormatException 。

@Overridepublic B aToB(A car) {if ( car == null ) {return null;}B b = new B();b.setName( car.getName() );if ( car.getNumber() != null ) { // 问题出在这里b.setNumber( Long.parseLong( car.getNumber() ) );}b.setIds( integerListToStringList( car.getIds() ) );return b;}

使用 cglib 默认则不会映射 number 属性,B 中的 number 为 null。另外,搜索公众号互联网架构师后台回复“2T”,获取一份惊喜礼包。


如果手动定义转换器,使用 IDEA 插件(如 generateO2O)自动转换:

public final class A2BConverter {public static B from(A first) {B b = new B();b.setName(first.getName());b.setIds(first.getIds());return b;}
}

在编码阶段就可以非常明确地发现这个问题:

3. 结论

由于 Java 的泛型其实是编译期检查,编译后泛型擦除,导致运行时 List<Integer> 和 List<String> 都是 List 类型,可以正常赋值。这就导致在使用很多属性映射工具时,编译时不容易明显的错误。

mapstruct 自定义了注解处理器,在编译阶段可以读取映射双方的泛型类型,进而进行映射。但是这种映射也很可怕,有时候我们由于粗心等原因定义错了类型,自动帮助我们进行了转换,会带了很多副作用。

之前对各种属性映射工具的性能进行了简单的对比,结果如下:

因此慎用属性转换工具,如果可能建议自定义转换类,使用 IDEA插件自动填充,效率也挺高, A 或 B 中任何属性类型不匹配,甚至删除一个属性,编译阶段即可报错,而且直接调用 get set 的效率也是非常高的。

危险!请马上替换代码中的BeanUtils!!!相关推荐

  1. 并发危险:解决多线程代码中的 11 个常见的问题

    本文将介绍以下内容: 基本并发概念 并发问题和抑制措施 实现安全性的模式 横切概念 本文使用了以下技术:  多线程..NET Framework 目录 数据争用  忘记同步  粒度错误  读写撕裂  ...

  2. 在keil5中如何替换代码中的关键字

    在界面左上角点击"edit"→"replace"(如图所示)

  3. sublime text3快速查找和替换代码

    在使用sublime text3敲代码时,经常需要快速查找和替换代码中的某个词,下面给大家介绍几种快速有效的解决方法. 查找.替换: 当需要查找某一个关键字出现的其它位置时,只需要使用Shift + ...

  4. 直播代码中关于敏感词替换的代码编辑

    想要在直播代码中实现字符串过滤的方式有很多种,每种编程语言都有相应的处理方式,且因语言不同,其所使用的函数也有所不同,但最终的目的都是为达到用户的绿色上网.安全上网,呈现给用户一种安全舒适的上网环境. ...

  5. 请确保此代码文件中定义的类与“inherits”属性匹配,并且该类扩展的基类(例如Page 或UserControl)是正确的。...

    编译ASP.NET时,提示"请确保此代码文件中定义的类与"inherits"属性匹配,并且该类扩展的基类(例如Page 或UserControl)是正确的.", ...

  6. php根据不同的条件替换一段html代码中的不同的img标签

    一.需求 这次的需求是获取到一段html代码,这段代码里面含有多个img标签.需求就是先获取到这些img标签的src属性,然后进行业务编写.业务编写之后,把新的src内容分别替换到不同的img标签中. ...

  7. php中的eq的含义,jquery,_jQuery中的eq(0)到底是什么意思??详情请看下面代码!,jquery - phpStudy...

    jQuery中的eq(0)到底是什么意思??详情请看下面代码! 手风琴效果 *{padding:0; margin:0;} .box{margin:50px auto; width:300px; he ...

  8. 状态栏和navigationbar 关联上,结构体总是通过被复制的方式在代码中传递,因此请不要使用引用计数。...

    @interface MapDetailViewController ()<UINavigationBarDelegate> - (UIBarPosition)positionForBar ...

  9. php 替换指定标签中的内容,php如何根据不同的条件替换html代码中的img标签

    这篇文章给大家介绍的内容是关于php根据不同的条件替换一段html代码中的不同的img标签,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 一.需求 这次的需求是获取到一段html代码 ...

  10. 请确保此代码文件中定义的类与“inherits”属性匹配.并且该类扩展的基类(例如 Page 或 UserControl)是正确...

    遇到这个问题 特此记录一下 由于copy   aspx页面 引起的 copy之后   类名实原来那个的跟 你现在的文件名不一样LoginAPI.aspx public partial class yu ...

最新文章

  1. 2018-4-17论文《狼群算法的研究与应用》笔记2 :高维复杂单目标连续优化问题的改进狼群算法
  2. 基于VTK User Guide和VTK Textbook学习
  3. Exp2 后门原理与实践 20164309
  4. SVN 服务端、客户端安装及配置、导入导出项目
  5. 报错:The type javax.servlet.http.HttpServletRequest cannot be resolved
  6. Java Platform Module系统中的可选依赖项
  7. 终端安全 | 全面适配国产系统,打造政企合规终端
  8. Express框架使用以及数据库公共操作类整理(Win7下的NodeJs)
  9. php对象方法调用静态方法,php面向对象之静态方法使用
  10. django get和filter方法的几点不同
  11. 艾宾浩斯遗忘曲线.pdf百日计划表.pdf考研时间计划表.pdf每日打卡.pdf每日复习计划表.pdf详细日计划.pdf月计划表.pdf周计划.pdf
  12. w10共享网络没有计算机,在W10局域网内找不到其它共享电脑的解决方案
  13. solaris 命令大全
  14. 挂载命令 mount
  15. 解决前端做excel下载的文件打不开
  16. python-名字按拼音排序-(用pypinyin)
  17. python像数常用函数_八卦象数疗法的作用机理探讨
  18. java 代码覆盖率
  19. 美团后台面试经验参考
  20. 数据库MySQL-查询语句

热门文章

  1. javascript案例---简单的视觉效应
  2. SpringCloud微服务云架构构建B2B2C电子商务平台之-服务的注册与发现Eureka
  3. 1075. PAT Judge (25)
  4. 面向资源的权限体系设计随想
  5. 自定义圆形进度条ProgressBar
  6. 大连市2011年初中毕业升学考试试测(一)数 学
  7. 「代码随想录」动态规划:关于完全背包,你该了解这些!
  8. hdu 1054 Strategic Game 树形dp基础模板
  9. hdu 4315 Climbing the Hill 博弈问题,可转化为nim游戏问题,多校联合赛(二)第六题
  10. DjVu Reader Pro for Mac(DjVu阅读软件)