1.1 什么是dozer?
Dozer 是一个对象转换工具。
Dozer可以在JavaBean到JavaBean之间进行递归数据复制,并且这些JavaBean可以是不同的复杂的类型。
所有的mapping,Dozer将会很直接的将名称相同的fields进行复制,如果field名不同,或者有特别的对应要求,则可以在xml中进行定义。
更多详细请参考dozer官网:http://dozer.sourceforge.net/documentation/about.html
1.2 为什么要使用Dozer?
分析多层架构的J2EE系统,经常存在JavaBean直接的拷贝。比如我们在DAO层,通过Do取得业务层需要的数据,将这些数据传递给 Service层的VO。Do与VO就存在典型的值拷贝。
典型的解决方案就是手动拷贝,弊端很明显,代码中充斥大量Set 和Get方法,真正的业务被埋藏值与值的拷贝之中。另一种方案就是使用BeanUtil,但BeanUtil不够很好的灵活性,又时候还不得不手动拷贝。Dozer可以灵活的对对象进行转换,且使用简单。
Dozer其实底层使用了现成的BeanUtil,通过反射来映射,况且Dozer应用了Cache技术,应该比自个通过BeanUtils映射性能要好点。所以一般的应用应该不存在性能问题。
注意:Dozer支持简单类型 复杂类型的双向递归映射。
1.3 如何得到Dozer 工具类jar包
1. 点击下载:http://sourceforge.net/projects/dozer/files/
本文中使用的版本是dozer-5.3.2
2. Dozer 支持的转换类型
Dozer支持
Primitive 基本数据类型 , 后面带 Wrapper 是包装类 Complex Type 是复杂类型
• Primitive to Primitive Wrapper
• 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
• Collection to Collection
• Collection to Array
• Map to Complex Type
• Map to Custom Map Type
• 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
• String to any of the supported Date/Calendar Objects.
• Objects containing a toString() method that produces a long representing time in (ms) to any supported Date/Calendar object
3 Dozer使用(不与spring集成下)
3.1 dozer使用分类
根据有无映射文件和文件的多少,有三种方式:
第一种:该方式用于数据类型为基本类型,名称相同的对象映射
Mapper mapper = new DozerBeanMapper();
SourceObject sourceObject = new SourceObject();
DestinationObject destObject = (DestinationObject) mapper.map(sourceObject, DestinationObject.class);
// or
DestinationObject destObject = new DestinationObject();
mapper.map(sourceObject, destObject);
第二种:该方式用于数据类型不一致,或者名称不相同或者有级联关系等情况下的映射,该方式可以添加多个配置文件dozerBeanMapping.xml、someOtherDozerBeanMappings.xml 等
List myMappingFiles = new ArrayList();
myMappingFiles.add("dozerBeanMapping.xml");
//myMappingFiles.add("someOtherDozerBeanMappings.xml");
DozerBeanMapper mapper = new DozerBeanMapper();
SourceObject sourceObject = new SourceObject();
mapper.setMappingFiles(myMappingFiles);
DestinationObject stObject=
(DestinationObject) mapper.map(sourceObject, DestinationObject.class);
第三种:该方式用于数据类型不一致,或者名称不相同或者有级联关系等情况下的映射,配置文件只有一个映射文件叫dozerBeanMapping.xml且在根目录下
Mapper mapper = DozerBeanMapperSingletonWrapper.getInstance();
SourceObject sourceObject = new SourceObject();
DestinationObject destObject = (DestinationObject) mapper.map(sourceObject, DestinationObject.class);
//or
//Mapper mapper = DozerBeanMapperSingletonWrapper.getInstance();
//DestinationObject destObject = new DestinationObject();
mapper.map(sourceObject, destObject);
3.2 举例说明:
假设我们现在有一个userVo类,如下:
/**
*
*/
package com.wy.bean;
/**
* @author wy
*
*/
public class UserVO {
private int id;
private String userName;
private String password;
private InfoVO infoVo;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public InfoVO getInfoVo() {
return infoVo;
}
public void setInfoVo(InfoVO infoVo) {
this.infoVo = infoVo;
}
@Override
public String toString() {
return "UserVO [id=" + id + ", userName=" + userName + ", password="
+ password + ", infoVo=" + infoVo + "]";
}
}
一个User类,如下:
/**
*
*/
package com.wy.bean;
/**
* @author wy
*
*/
public class User {
private int id;
private String name;
private String password;
private Info info;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Info getInfo() {
return info;
}
public void setInfo(Info info) {
this.info = info;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", password=" + password
+ ", info=" + info + "]";
}
}
一个InfoVo类,如下:
/**
*
*/
package com.wy.bean;
/**
* @author wy
*
*/
public class InfoVO {
private int id;
private String date;
private Integer gender;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public Integer getGender() {
return gender;
}
public void setGender(Integer gender) {
this.gender = gender;
}
@Override
public String toString() {
return "InfoVO [id=" + id + ", date=" + date + ", gender=" + gender
+ "]";
}
}
一个Info类,如下:
/**
*
*/
package com.wy.bean;
/**
* @author wy
*
*/
import java.util.Date;
public class Info {
private int id;
private Date createDate;
private GenderType gender;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
public GenderType getGender() {
return gender;
}
public void setGender(GenderType gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Info [id=" + id + ", createDate=" + createDate + ", gender="
+ gender + "]";
}
}
一个枚举类,如下:
package com.wy.bean;
public enum GenderType {
male,//男
female//女
}
3.2.1 字段名称不同映射配置
<mapping>
<class-a>ce.dozer.User</class-a>
<class-b>ce.dozer.UserVO</class-b>
<field>
<a>name</a>
<b>userName</b>
</field>
</mapping>
3.2.2 Date与String映射配置如下:
<mapping date-format="yyyy-MM-dd">
<class-a>ce.dozer.User</class-a>
<class-b>ce.dozer.UserVO</class-b>
<field>
<a>info.createDate</a>
<b>info.date</b>
</field>
</mapping>
3.2.3 在示例中我们看到在userDo和userVo对象中关联了其他的对象,这个问题不用担心,因为对象名称相同dozer会为我们自动转换。而问题不在这,在与对象中有枚举类型,我们该怎么写配置呢?在这里我们就必须自己编写一个处理类来处理枚举与Integer的转换了(假设我们的处理类为util.EnumIntConverter),配置如下:
<configuration> <stop-on-errors>true</stop-on-errors> <date-format>yyyy-MM-dd</date-format> <wildcard>true</wildcard> <custom-converters> <converter type=" util.EnumIntConverter"> <class-a>java.lang.Enum</class-a> <class-b>java.lang.Integer</class-b> </converter> </custom-converters> </configuration> <mapping> <class-a>ce.dozer.User</class-a> <class-b>ce.dozer.UserVO</class-b> <field> <a>info.gender</a> <b>info.gender</b> </field> </mapping>
最终的dozerBeanMapping.xml 配置文件:
<?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"> <configuration> <stop-on-errors>true</stop-on-errors> <date-format>yyyy-MM-dd</date-format> <wildcard>true</wildcard> <custom-converters> <converter type="com.wy.util.EnumIntConverter"> <class-a>java.lang.Enum</class-a> <class-b>java.lang.Integer</class-b> </converter> </custom-converters> </configuration> <!--Date与String映射配置--> <mapping date-format="yyyy-MM-dd hh:mm:ss"> <class-a>com.wy.bean.User</class-a> <class-b>com.wy.bean.UserVO</class-b> <field> <a>info.createDate</a> <b>infoVo.date</b> </field> <field> <a>info.gender</a> <b>infoVo.gender</b> </field> <!-- 字段名称不同映射配置 --> <field> <a>name</a> <b>userName</b> </field> </mapping> </mappings>
EnumIntConverter类,如下:
/**
*
*/
package com.wy.util;
import org.dozer.CustomConverter;
import com.wy.bean.GenderType;
/**
* @author wy
*
*/
public class EnumIntConverter implements CustomConverter {
public Object convert(Object destinationFieldValue, Object sourceFieldValue, Class<?> destinationClass, Class<?> sourceClass) {
Object returnVale = null;
if (sourceFieldValue != null) {
if (sourceFieldValue instanceof Integer) {
if ((Integer) sourceFieldValue == 0) {
returnVale = GenderType.male;
} else if ((Integer) sourceFieldValue == 1) {
returnVale = GenderType.female;
}
} else if (sourceFieldValue instanceof Enum) {
if (sourceFieldValue == GenderType.male) {
returnVale = 0;
} else if (sourceFieldValue == GenderType.female) {
returnVale = 1;
}
}
}
return returnVale;
}
}
4 与spring的集成
4.1 1、dozer 要与spring集成需要将dozer交给spring管理,配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd"
default-autowire="byName" default-lazy-init="false">
<bean id="mapper" class="org.dozer.spring.DozerBeanMapperFactoryBean">
<property name="mappingFiles">
<list>
<value>classpath*:dozerBeanMapping.xml</value>
</list>
</property>
</bean>
</beans>
4.2 2、当我们的dozer交给了spring管理,当spring容器启动后我们可以将下面的代码添加到用于继承的基类中去:
private Mapper mapper;
public Mapper getMapper() {
return mapper;
}
public void setMapper(Mapper mapper) {
this.mapper = mapper;
}
4.33、在继承者类中就可以直接如下使用:
getMapper().map(sourceObject, DestinationObject.class)
5 结束语
Dozer的转换功能很强大,我们所能想到的类型转换,它基本都可以帮助我们完成。所以如果您想对dozer了解更多更深,建议到官网仔细阅读相关文档和说明!
官网:http://dozer.sourceforge.net/documentation/mappings.html
转载:http://seyaa.iteye.com/blog/762494