详谈 JAVA对象拷贝

详谈 JAVA对象拷贝

引出

对象拷贝对于开发说书司空见惯,java从工具类到框架,对于这个功能都有实现的方法,一下就是实现的几种方法。

方法一

原始的getset方式
我是比较常用这个做法的,比如现在DemoDTO删去某个字段,编译器就会报错,就会引起你的注意了,让问题提前暴露。

DemoDTO demoDTO = new DemoDTO();
demoDTO.setId(RandomUtil.uuId());
demoDTO.setOrganizeId(demoEntity.getOrganizeId());
demoDTO.setObjectType(demoEntity.getPosition());
demoDTO.setObjectId(demoEntity.positionId());

缺点大概就是,显得代码非常冗余。确实好修改。

方法二(不推荐)

很多主流的java工具包中的 BeanUtil.copyProperties()
比较知名的大概就是hutool了。

 // 前端传输的对象
DiagramDTO diagramDTO = new DiagramDTO();
// 如果前端传入的id事包含e的,升级后就会报错
diagramDTO.setId("xxxx");
diagramDTO.setCode("encodeXXXX");
diagramDTO.setName("图表");
Diagram diagram = new Diagram();
// 关键点,数据拷贝
BeanUtil.copyProperties(diagramDTO, diagram);
System.out.println("数据实体对象:" + diagram);

相信这个算是很主流的一个写法了,但事实上包含了一些较为严重的缺陷。
在早期的5.7.2版本之前的Hutool中,虽然字段类型不一样,但是做了兼容处理,所以没有影响业务逻辑。
举个例子:

// DTO中
private String id;
// Entity中
private Integer id;

此时是没有问题可以转换的。
升级后,执行报错,因为升级后的版本修改了实现,增加了下面的逻辑,如果包含E, 就会抛错,从而影响了业务逻辑,同时这个id是否包含e又是随机因素。

if(StrUtil.containsIgnoreCase(number,"E")){
    // 科学计数法忽略支持,科学计数法一般用于表示非常小和非常大的数字,这类数字转换为int后精度丢失,没有意义。
    throw new NumberFormatException(StrUtil.format("Unsupported int format:[{}]"number));
}

从而,团队中的某些人偷偷改了数据传输对象DTO,比如修改了类型、删去了某个字段。用BeanUtil.copyProperties的方式压根无法在编译阶段发现,更别提修改的影响范围了,这就只能把风险暴露到生产上去了

现在我们怎么做的?

方法三 (MapStruct)

MapStruct也是Java中另外一个用于映射对象很流行的开源工具。它是在编译阶段生成对应的映射代码,相对于ModelMapper底层映射的方案,性能更好。也保留了在编译时暴露映射错误的代码,让错误提前暴露。

// 使用了`@Mapper`注解,用来表明使用`MapStruct`处理
@Mapper
public interface MouldInfoConvert {
    MouldInfoConvert INSTANCE = Mappers.getMapper(MouldInfoConvert.class);
    MouldInfo convert(MouldInfoDto mouldInfoDto);
    MouldInfoDto convert(MouldInfo mouldInfo);
    List<MouldInfoDto> convert2DtoList(List<MouldInfo> list);
    List<MouldInfo> convert2EntityList(List<MouldInfoDto> list);
}
// 使用
List<MouldInfoDto> mouldInfoDtos = MouldInfoConvert.INSTANCE.convert2DtoList(list);

MapStruct的本质就是在编译时生成相应的实现方法(get/set)
还有许多高级的用法,例如不同名字的字段的映射添加自定义方法多个源参数映射等等。

多说一句 One more thing

IDEA中可以直接安装Mapstruct Support插件

  1. 突出显示目标属性和源属性。将目标属性和源属性转到声明的setter / getter中;
  2. 错误和快速修复:
  3. 缺少@Mapper或@MapperConfig注解检查;
  4. 快速修复未映射的目标属性,添加未映射目标属性和忽略未映射目标属性;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值