java bean转换工具比较

java bean的转换工具目前主要有两大类,一类是通过反射实现的,如BeanUtils,一类是通过直接映射字节码实现的,如BeanCopier、Orika等。个人觉得这两类在性能上根本没有可比性。但是项目中总有人对BeanUtils这个工具类有种莫名的执着,因此本文将从bean转换的正确性、时间效率和易用性三个方面来比较BeanUtils、BeanCopier和Orika。
定义一个稍复杂点儿的实体类

private String field1;
    private String field2;
    private String field3;
    private Strin field4;
    private String field5;
    private String field6;
    private String field7;
    private String field8;
    private String field9;
    private String field10;
    private List<ListBean> field11;
    private Map<String, MapBean> field12;

1. 比较正确性:

三个工具均能正确复制bean的各个属性;

2. 比较时间效率:
BeanUtils

long start = System.currentTimeMillis();
        for(int i= 0; i<10000; i++) {
            BeanUserCopy beanUserCopy = new BeanUserCopy();
            BeanUtils.copyProperties(user, beanUserCopy);
        }
        long end = System.currentTimeMillis();
        System.out.println("BeanUtils耗时:"+(end - start));

BeanCopier

BeanCopier copier = BeanCopier.create(BeanUser.class, BeanUserCopy.class, false);
        long startCopier = System.currentTimeMillis();
        for(int i= 0; i<10000; i++) {
            BeanUserCopy beanUserCopy = new BeanUserCopy();
            copier.copy(user, beanUserCopy, null);
        }
        long endCopier = System.currentTimeMillis();
        System.out.println("BeanCopier耗时:"+(endCopier - startCopier));

Orika

MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
        MapperFacade mapper = mapperFactory.getMapperFacade();
        long startMapper = System.currentTimeMillis();
        for(int i= 0; i<10000; i++) {
            BeanUserCopy beanUserCopy = new BeanUserCopy();
            beanUserCopy = mapper.map(user, BeanUserCopy.class);
        }
        long endMapper = System.currentTimeMillis();
        System.out.println("MapperFacade耗时:"+(endMapper - startMapper));

执行10000次复制所用时间,单位ms:
BeanUtils:1623
BeanCopier:12
Orika:1460
很奇怪,Orika的性能完全不如预期???
在增加classMap之后耗时大幅度降低了

mapperFactory.classMap(BeanUser.class, BeanUserCopy.class)
                .register();

最后10000次复制耗时331。
3. 比较易用性:
(1)缺少set方法的情况
当我故意将目标类中某个属性的set方法去掉之后,BeanUtils和BeanCopier还是能成功复制,但是缺少set方法的属性不会复制,而Orika直接报错了。
(2)类型相同名称不同的属性转换
三者结果一致,被修改属性名的那项都转换失败了。
orika提供如下的方法注册字段映射:

mapperFactory.classMap(BeanUser.class, BeanUserCopy.class)
                .field("field2","change2")
                .byDefault()
                .register();

orika的映射还是很强大的,不仅可以映射这样的简单属性,还可以映射数组、List、类属性。
(3)类型不同名称相同的属性转换
将源bean中某一属性类型改为int,目标bean中改为Integer,BeanUtils和Orika转换成功了,而BeanCopier失败。
(4)自定义转换器
BeanCopier
修改源bean

private String field1;
    private String field2;
    private Integer field3;
    private Date field4;
    private String field5;
    private String field6;
    private String field7;
    private String field8;
    private String field9;
    private String field10;
    private List<ListBean> field11;
    private Map<String, MapBean> field12;

目标bean

private String field1;
    private String change2;
    private int field3;
    private String field4;
    private String field5;
    private String field6;
    private String field7;
    private String field8;
    private String field9;
    private String field10;
    private List<ListBean> field11;
    private Map<String, MapBean> field12;

定义转换器

class DateConverterBeanCopier implements Converter {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Override
    public Object convert(Object value, Class target, Object context) {
        if(value instanceof Date){
            Date date = (Date) value;
            return sdf.format(date);
        }else if(value instanceof Integer){
            return (Integer)value;
        }
        return null;
    }
}
BeanUserCopy beanUserCopyTest2 = new BeanUserCopy();
        BeanCopier copierTest = BeanCopier.create(BeanUser.class, BeanUserCopy.class, true);
        DateConverterBeanCopier converterBeanCopier = new DateConverterBeanCopier();
        copierTest.copy(user, beanUserCopyTest2, converterBeanCopier);

除change2都转换成功了,也就是说同名不同类型的属性BeanCopier可以通过转换器实现。
Orika
定义转换器

//Date为源bean中类型,String为目标bean中类型
class DateConverterOrika extends CustomConverter<Date,String> {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Override
    public String convert(Date date, Type<? extends String> type, MappingContext mappingContext) {
        return sdf.format(date);
    }
}
MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
        DateConverterOrika dateConverterOrika = new DateConverterOrika();
        ConverterFactory converterFactory = mapperFactory.getConverterFactory();
        converterFactory.registerConverter("myDateConverter", dateConverterOrika);
        mapperFactory.classMap(BeanUser.class, BeanUserCopy.class)
                .field("field2","change2")
                .byDefault()
                .fieldMap("field4")//field4为需要使用转换器的属性名
                .converter("myDateConverter").add()
                .register();
        MapperFacade mapper = mapperFactory.getMapperFacade();
        BeanUserCopy beanUserCopyTest3 = mapper.map(user, BeanUserCopy.class);

完美转换所有属性。

4. 总结
(1)orika映射功能很好用,在不适用转换器的情况下BeanCopier只会复制同名同类型的属性,即使int和Integer也会被BeanCopier认为是两种类型。
(2)orika和BeanCopier都支持自定义转换器,orika的转换器灵活度更高,但配置也会相对复杂一些。
(3)性能上还是BeanCopier胜出,在复制同名同类型属性时优先选择BeanCopier。

发布了26 篇原创文章 · 获赞 8 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_36142042/article/details/84931600