麻了,不要再动不动就BeanUtil.copyProperties

科技资讯 投稿 6600 0 评论

麻了,不要再动不动就BeanUtil.copyProperties

前言

hutool的版本,以解决安全漏洞问题,这不升级还好,一升级反而捅出了更大的篓子,究竟是怎么回事呢?

事件回顾

hutool版本是5.7.2,在代码中,我们的数据传输对象DTO和数据实体对象中大量使用了工具包中的BeanUtil.copyProperties(, 大体代码如下:

    数据传输对象
@Data
@ToString
public class DiagramDTO {

    // 前端生产的字符串id
    private String id;

    private String code;

    private String name;
}
  1. 数据实体对象
@Data
@ToString
public class Diagram {

    private Integer id;

    private String code;

    private String name;
}
  1. 业务逻辑
public class BeanCopyTest {

    public static void main(String[] args {
        // 前端传输的对象
        DiagramDTO diagramDTO = new DiagramDTO(;
        // 如果前端传入的id事包含e的,升级后就会报错
        diagramDTO.setId("3em3dgqsgmn0";
        diagramDTO.setCode("d1";
        diagramDTO.setName("图表";

        Diagram diagram = new Diagram(;
        // 关键点,数据拷贝
        BeanUtil.copyProperties(diagramDTO, diagram;
        System.out.println("数据实体对象:" + diagram;
        //设置id为空,自增
        diagram.setId(null;
        //保存到数据库中 TODO
        //diagramMapper.save(diagram;
    }
}

升级前,hutool是5.7.2版本下,执行结果如下图。

    BeanUtil.copyProperties虽然字段类型不一样,但是做了兼容处理,所以业务没有影响业务逻辑。

hutool是5.8.8版本,执行结果如下图所示:

    执行报错,因为升级后的版本修改了实现,增加了下面的逻辑,如果包含E, 就会抛错,从而影响了业务逻辑,同时这个id是否包含e又是随机因素,到了生产才发现,就悲剧了。

分析探讨

BeanUtil.copyProperties用的一时爽,但有时候带来的后果是很严重的,所以很不推荐这种方式。为什么这么说呢?

BeanUtil.copyProperties的方式压根无法在编译阶段发现,更别提修改的影响范围了,这就只能把风险暴露到生产上去了。那有什么更好的方法呢?

推荐方案

    原始的getset方式

DiagramDTO删去某个字段,编译器就会报错,就会引起你的注意了,让问题提前暴露,无处遁形。

  1. 使用开源库ModelMapper
ModelMapper是一个开源库,可以很方便、简单地将对象从一种类型映射到另一种类型,底层是通过反射来自动确定对象之间的映射,还可以自定义映射规则。
 private static void testModelMapper( {
        ModelMapper modelMapper = new ModelMapper(;
        DiagramDTO diagramDTO = new DiagramDTO(;
        diagramDTO.setId("3em3dgqsgmn0";
        diagramDTO.setCode("d1";
        diagramDTO.setName("图表";
        Diagram diagram = modelMapper.map(diagramDTO, Diagram.class;
    }
  1. 使用开源库MapStruct
MapStruct也是Java中另外一个用于映射对象很流行的开源工具。它是在编译阶段生成对应的映射代码,相对于ModelMapper底层放射的方案,性能更好。
@Mapper
public interface DiagramMapper {
    DiagramMapper INSTANCE = Mappers.getMapper(DiagramMapper.class;

    DiagramDTO toDTO(Diagram diagram;

    Diagram toEntity(DiagramDTO diagram;
}

private static void testMapStruct( {
    DiagramDTO diagramDTO = new DiagramDTO(;
    diagramDTO.setId("3em3dgqsgmn0";
    diagramDTO.setCode("d1";
    diagramDTO.setName("图表";
    Diagram diagram = DiagramMapper.INSTANCE.toEntity(diagramDTO;
}
    DiagramMapper接口使用了@Mapper注解,用来表明使用MapStruct处理
  • MapStruct中更多高级特性大家自己探索一下。

总结

小结一下,对象在不同层之间进行转换映射,很不建议使用BeanUtil.copyProperties这种方式,更加推荐使用原生的set, get方式,不容易出错。当然这不是将BeanUtil.copyProperties一棒子打死,毫无用武之地,在特定场景,比如方法内部对象的转换等影响小的范围还是很方便的,如果你有其他的想法,也可以留下你的想法,一起探讨交流。

欢迎关注个人公众号【JAVA旭阳】交流学习!

编程笔记 » 麻了,不要再动不动就BeanUtil.copyProperties

赞同 (36) or 分享 (0)
游客 发表我的评论   换个身份
取消评论

表情
(0)个小伙伴在吐槽