Dozer推土机。。

      以前通常使用的都是Jakarta Commons BeanUtils 包来做bean之间的属性拷贝,这次在看springside3.1的时候发现了里面推荐Dozer来做,而不是BeanUtils包很是纳闷。于是上Dozer官网进行了一番查看,作了一些学习笔记的摘要。
      其实看老外写的英文文档还是很舒服的,没有晦涩的语句和单词,反而觉得那些高手写出来的寥寥几句话蕴含了一种技术高度的积累,可以体会到另一层面的思路。言归正传

一。Why Map?

为什么要做Mapping的映射?特别是在使用Webservice和Hessian等垮系统模块的时候,Model对象通常使用DTO解耦,eg。(springsied的例子)

 

Web Service传输Role信息的DTO.
package org.springside.examples.miniservice.ws.user.dto;

import javax.xml.bind.annotation.XmlType;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.springside.examples.miniservice.ws.Constants;

/**
 * Web Service传输Role信息的DTO.
 * 
 * 使用JAXB 2.0的annotation标注JAVA-XML映射,尽量使用默认约定.
 * 
 * @author calvin
 */
@XmlType(name = "Role", namespace = Constants.NS)
public class RoleDTO {

	private Long id;
	private String name;

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	/**
	 * 重新实现toString()函数方便在日志中打印DTO信息.
	 */
	@Override
	public String toString() {
		return ToStringBuilder.reflectionToString(this);
	}
}

在自己的系统内部,定义User类,

package org.springside.examples.miniservice.entity.user;
public class User extends IdEntity {
}

 使用Dozer来进行转换,将外部Webservice参数对象map到系统内部的user对象

List<User> userList = userManager.getAll();
List<UserDTO> userDTOList = new ArrayList<UserDTO>();
	for (User userEntity : userList) {
		userDTOList.add((UserDTO) dozer.map(userEntity, UserDTO.class));
}

Dozer主页上的解释:

For distributed systems, a side effect is the passing of domain objects between different systems. Typically, you won't want internal domain objects exposed externally and won't allow for external domain objects to bleed into your system.

Data object mapping is an important part of layered service oriented architectures. Pick and choose the layers you use mapping carefully. Do not go overboard as there is maintenance and performance costs associated with mapping data objects between layers.

Mapping between data objects has been traditionally addressed by hand coding value object assemblers (or converters) that copy data between the objects. Most programmers will develop some sort of custom mapping framework and spend countless hours and thousands of lines of code mapping to and from their different data object.  


二。 chooice :Jakarta Commons Bean Utils package ,Dozer

Dozer supports simple property mapping, complex type mapping, bi-directional mapping, implicit-explicit mapping, as well as recursive mapping. This includes mapping collection attributes that also need mapping at the element level.

可以明显的看到,Dozer支持复杂映射,自定义配置映射。相比起Beanutil的方法,显然可以做到更多的事情。(即便是默认的转换,Dozer也能够自动完成一样变量名字段之间的类型转换)


三。试用一把


step1

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

 step2 :Specifying Custom Mappings via XML

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mappings PUBLIC "-//DOZER//DTD MAPPINGS//EN"
   "http://dozer.sourceforge.net/schema/beanmapping.xsd">
<mappings>
  <configuration>
    <stop-on-errors>true</stop-on-errors>
    <date-format>MM/dd/yyyy HH:mm</date-format>
    <wildcard>true</wildcard>
  </configuration>

  <mapping>
    <class-a>yourpackage.yourSourceClassName</class-a>
    <class-b>yourpackage.yourDestinationClassName</class-b>
      <field>
        <A>yourSourceFieldName</A>
        <B>yourDestinationFieldName</B>
      </field>
  </mapping> 
            
  other custom class mappings would go here.......   
                   
</mappings>

 3.注入配置Injecting Custom Mapping Files

Dozer同样支持IOC容器的注入(现在很难找到不支持spring容器的项目了),同样也支持代码方式的注入:


The Dozer mapping xml file(s) define any custom mappings that can't be automatically performed by the Dozer mapping engine. Any custom Dozer mapping files need to be injected into the Mapper implementation(org.dozer.DozerBeanMapper). Both setter-based and constructor-based injection are supported.
Preferably, you will be using an IOC framework such as Spring for these Dozer injection requirements. Alternatively, the injection of mapping files can be done programatically. Below is a programmatic approach to creating a bean mapper. Note that this is NOT the recommended way to retrieve the bean mapper . Each new instance needs to be initialized and this consumes time as well as resources. If you are using the mapper this way just wrap it using the singleton pattern.


先看spring方式的注入:

<bean id="mapper" class="org.dozer.DozerBeanMapper">
  <property name="mappingFiles">
    <list>
      <value>dozer-global-configuration.xml</value>            
      <value>dozer-bean-mappings.xml</value>
      <value>more-dozer-bean-mappings.xml</value>
    </list>
  </property>
</bean>

 

再看代码方式的注入(!!!非推荐方式)

Each new instance needs to be initialized and this consumes time as well as resources. If you are using the mapper this way just wrap it using the singleton pattern.

List myMappingFiles = new ArrayList();
myMappingFiles.add("dozerBeanMapping.xml");
myMappingFiles.add("someOtherDozerBeanMappings.xml");
DozerBeanMapper mapper = new DozerBeanMapper();
mapper.setMappingFiles(myMappingFiles);
DestinationObject destObject = mapper.map(sourceObject, DestinationObject.class);
 

springside里面实现的Dozer单例:

package org.springside.modules.utils;

import net.sf.dozer.util.mapping.DozerBeanMapper;
import net.sf.dozer.util.mapping.MapperIF;

/**
 * 辅助DTO复制的Dozer工具类的单例wrapper.
 * 
 * Dozer在同一JVM里使用单例即可,无需重复创建.
 * 但Dozer4自带的DozerBeanMapperSingletonWrapper必须使用dozerBeanMapping.xml作参数初始化,因此重新实现无配置文件的版本.
 * 
 * @author calvin
 */
public final class DozerMapperSingleton {

	private static MapperIF instance = new DozerBeanMapper();//使用预初始化避免并发问题.

	private DozerMapperSingleton() {
	}

	public static MapperIF getInstance() {
		return instance;
	}
}

你可能感兴趣的:(spring,bean,xml,webservice,IOC)