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。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章