什么是Dozer

Dozer是一个Java对象转换工具,可以在JavaBean和JavaBean之间进行递归数据复制,并且适应不同复杂的类型。Dozer会直接将名称相同的属性进行复制,属性名不同或者有特殊的要求则可以在xml中进行配置。

除了使用Dozer,当然你还由其他选择:

典型的解决方案就是手动拷贝,弊端很明显,代码中充斥大量Set 和Get方法,真正的业务被埋藏值与值的拷贝之中。

另一种方案就是使用BeanUtil,但BeanUtil不够很好的灵活性,有时候还不得不手动拷贝。Dozer可以灵活的对对象进行转换,且使用简单。

Dozer做对象转换有什么特点 

默认属性Mapping,即如果属性名称一样, 就不需要显示配置,Dozer会自动处理。
自动做类型转换,即如果两个属性名称一样,即使类型不一样,在Dozer可理解范围内,帮你处理得妥妥的。Dozer可理解的类型范围非常广,这会极大的提升程序员的生产力
不必担心中间的null property,遇到null property,Dozer会把对应的所有属性全部设置为null,而不会抛NullPointerExeception。

Dozer可以自动做数据类型转换。当前,Dozer支持以下数据类型转换(都是双向的)(注:Primitive 基本数据类型 , 后面带 Wrapper 是包装类,Complex Type 是复杂类型。):

•   Primitive to Primitive Wrapper 
  原型(int、long等)和原型包装类(Integer、Long) • Primitive to Custom Wrapper
  原型和定制的包装 • Primitive Wrapper to Primitive Wrapper
  原型包装类和包装类 • Primitive to Primitive
  原型和原型 • Complex Type to Complex Type
  复杂类型和复杂类型 • String to Primitive
  字符串和原型 • String to Primitive Wrapper
  字符串和原型包装类 • String to Complex Type if the Complex Type contains a String constructor
  字符串和有字符串构造器的复杂类型(类) • String 到复杂类型 , 如果复杂类型包含一个 String 类型的构造器 • String to Map
  字符串和Map • Collection to Collection
  集合和集合 • Collection to Array
  集合和数组 • Map to Complex Type
  Map和复杂类型 • Map to Custom Map Type
  Map和定制Map类型 • Enum to Enum
  枚举和枚举 • Each of these can be mapped to one another: java.util.Date, java.sql.Date, java.sql.Time, java.sql.Timestamp, java.util.Calendar, java.util.GregorianCalendar
  这些时间相关的常见类可以互换:java.util.Date, java.sql.Date, java.sql.Time, java.sql.Timestamp, java.util.Calendar, java.util.GregorianCalendar • String to any of the supported Date/Calendar Objects.
  字符串和支持Date/Calendar的对象 • Objects containing a toString() method that produces a long representing time in (ms) to any supported Date/Calendar object.
  如果一个对象的toString()方法返回的是一个代表long型的时间数值(单位:ms),就可以和任何支持Date/Calendar的对象转换。

在普通Java项目中使用Dozer

在pom.xml中增加依赖

<dependency>
  <groupId>net.sf.dozer</groupId>
  <artifactId>dozer</artifactId>
  <version>5.5.1</version>
</dependency> 

使用Dozer进行类转换

public class Main {

    public static void main(String[] args) {
        DozerBeanMapper mapper = new DozerBeanMapper();
        UserDO userDO = new UserDO();
        userDO.setName("hollis");
        userDO.setAddress("hz");
        userDO.setAge(25);
        userDO.setCompanyId(1);
        userDO.setBirthday(new Date());
        userDO.setGender("male");
        userDO.setEducation("1");
        userDO.setNickName("hollis");
        userDO.setPoliticalStatus("3");
        UserVO userVO = (UserVO) mapper.map(userDO, UserVO.class);
        System.out.println(userVO);
    }
} 

特殊的字段转换
在使用mapper进行转换前,设置一个或多个mapping文件

List myMappingFiles = new ArrayList();    
myMappingFiles.add("dozer-mapping.xml");    
mapper.setMappingFiles(myMappingFiles); 

配置dozer-mapping.xml文件

数据类型不一致,或者名称不相同或者有级联关系等情况下,可以通过文件dozer-mapping.xml来进行定制Bean的转换

<?xml version="1.0" encoding="UTF-8"?>
<mappings xmlns="http://dozer.sourceforge.net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://dozer.sourceforge.net
          http://dozer.sourceforge.net/schema/beanmapping.xsd">
    <mapping>
        <class-a>com.hollis.lab.UserDO</class-a>
        <class-b>com.hollis.lab.UserVO</class-b>
    </mapping>
</mappings> 

在JavaWeb项目中使用Dozer

在pom.xml中增加依赖

<dependency>
  <groupId>net.sf.dozer</groupId>
  <artifactId>dozer</artifactId>
  <version>5.5.1</version>
</dependency> 

使用Spring集成dozer

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <bean id="baseMapper" class="org.dozer.spring.DozerBeanMapperFactoryBean">
        <property name="mappingFiles">
            <list>
                <value>classpath:mapping/dozer-mapping.xml</value>
            </list>
        </property>
    </bean> 
</beans> 

使用baseMapper进行Bean的转换

@Autowired
private Mapper baseMapper;
private UserVO doToVo(UserDO userDO){
    if(userDO == null) return null;
    UserVO vo = baseMapper.map(userDO, UserVO.getClass());
    if(userDO.getCompanyId != null) getCompany(vo);
    return vo;
} 

通过以上的代码加配置,我们就实现了从DO转换到VO的部分操作,之所以说是部分操作,是因为我们在dozer-mapping.xml并没有做多余的配置,只是使用dozer将DO中和VO中共有的属性转换了过来。对于其他的类型不同或者名称不同等的转换可以参考官网例子通过设置dozer-mapping.xml文件来实现。

上面还有一个getCompany()没有实现。这个方法其实就是通过companyId查询出company实体然后在赋值给UserVO中的company属性。

注意事项

1:

DestinationObject destObject =  mapper.map(sourceObject, DestinationObject.class);

DestinationObject必须有无参构造方法,不然会报java.lang.NoSuchMethodException: com.net.vo.CompanyVo.<init>()错误。

2:

SourceObject和DestinationObject中属性必须可读写,比如提供公开的get或set方法,不然无法复制数据。其实,转化的过程是通过调用UserDO中的getter方法和UserVO中的setter方法来实现的。

3:

dozer正常输出日志需要增加两个jar包

slf4j-api和slf4j-simple,或者,slf4j-api和slf4j-log4j12

例如:

<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.6.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-simple -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-simple</artifactId>
    <version>1.6.1</version>
</dependency> 

参考资料

使用Dozer优雅的将DO转换成VO:http://www.hollischuang.com/archives/1613

Dozer使用简记:http://tedhacker.top/2016/08/17/Dozer%E4%BD%BF%E7%94%A8%E7%AE%80%E8%AE%B0/

Dozer 使用小结:https://www.jianshu.com/p/bf8f0e8aee23