dozer

匿名 (未验证) 提交于 2019-12-02 22:56:40

maven方式:

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

NotSameAttributeA.java

public class NotSameAttributeA {     private long id;     private String name;     private Date date;      // 省略getter/setter }

NotSameAttributeB.java

public class NotSameAttributeB {     private long id;     private String value;     private Date date;      // 省略getter/setter }

这两个类存在属性名不完全相同的情况:name 和 value。

如果要映射的两个对象有完全相同的属性名,那么一切都很简单。
只需要直接使用Dozer的API即可:

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

但实际映射时,往往存在属性名不同的情况。

所以,你需要一些配置来告诉Dozer应该转换什么,怎么转换。

注:官网着重建议:在现实应用中,最好不要每次映射对象时都创建一个Mapper实例来工作,这样会产生不必要的开销。如果你不使用IoC容器(如:spring)来管理你的项目,那么,最好将Mapper定义为单例模式。

映射配置文件
在src/test/resources目录下添加dozer/dozer-mapping.xml文件。

<mapping>标签中允许你定义<class-a>和<class-b>,对应着相互映射的类。 <field>标签里定义要映射的特殊属性。需要注意<a>和<class-a>对应, <b>和<class-b>对应
<?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 date-format="yyyy-MM-dd">     <class-a>org.zp.notes.spring.common.dozer.vo.NotSameAttributeA</class-a>     <class-b>org.zp.notes.spring.common.dozer.vo.NotSameAttributeB</class-b>     <field>       <a>name</a>       <b>value</b>     </field>   </mapping> </mappings>

配置 DozerBeanMapperFactoryBean
在src/test/resources目录下添加spring/spring-dozer.xml文件。

Dozer与Spring的整合很便利,你只需要声明一个DozerBeanMapperFactoryBean,
将所有的dozer映射配置文件作为属性注入到mappingFiles,
DozerBeanMapperFactoryBean会加载这些规则。

spring-dozer.xml文件范例

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"        xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"        default-autowire="byName" default-lazy-init="false">    <bean id="mapper" class="org.dozer.spring.DozerBeanMapperFactoryBean">     <property name="mappingFiles">       <list>         <value>classpath*:dozer/dozer-mapping.xml</value>       </list>     </property>   </bean> </beans>
RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:spring/spring-dozer.xml"}) @TransactionConfiguration(defaultRollback = false) public class DozerTest extends TestCase {     @Autowired     Mapper mapper;      @Test     public void testNotSameAttributeMapping() {         NotSameAttributeA src = new NotSameAttributeA();         src.setId(007);         src.setName("邦德");         src.setDate(new Date());          NotSameAttributeB desc = mapper.map(src, NotSameAttributeB.class);         Assert.assertNotNull(desc);     } }

Dozer可以自动做数据类型转换。当前,Dozer支持以下数据类型转换(都是双向的)

  • 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 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的对象转换。

在前面的简单例子中,我们体验了一把Dozer的映射流程。但是两个类进行映射,有很多复杂的情况,相应的,你也需要一些更复杂的配置。

Dozer有三种映射配置方式:
注解方式
API方式
XML方式
用注解来配置映射
Dozer 5.3.2版本开始支持注解方式配置映射(只有一个注解:@Mapping)。可以应对一些简单的映射处理,复杂的就玩不转了。

看一下@Mapping的声明就可以知道,这个注解只能用于元素和方法。

@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.FIELD, ElementType.METHOD}) public @interface Mapping {   String value() default ""; }

TargetBean.java

public class SourceBean {      private Long id;      private String name;      @Mapping("binaryData")     private String data;      @Mapping("pk")     public Long getId() {         return this.id;     }      //其余getter/setter方法略 }

TargetBean.java

public class TargetBean {      private String pk;      private String name;      private String binaryData;      //getter/setter方法略 }

定义了两个相互映射的Java类,只需要在源类中用@Mapping标记和目标类中对应的属性就可以了。

@Test public void testAnnotationMapping() {     SourceBean src = new SourceBean();     src.setId(7L);     src.setName("邦德");     src.setData("00000111");      TargetBean desc = mapper.map(src, TargetBean.class);     Assert.assertNotNull(desc); }

用XML来配置映射
需要强调的是:如果两个类的所有属性都能很好的互转,可以你中有我,我中有你,不分彼此,那么就不要画蛇添足的在xml中去声明映射规则了。

属性名不同时的映射(Basic Property Mapping)
Dozer会自动映射属性名相同的属性,所以不必添加在xml文件中。

<field>   <a>one</a>   <b>onePrime</b> </field>

字符串和日期映射(String to Date Mapping)
字符串在和日期进行映射时,允许用户指定日期的格式。

格式的设置分为三个作用域级别:

属性级别

对当前属性有效(这个属性必须是日期字符串)

<field>   <a date-format="MM/dd/yyyy HH:mm:ss:SS">dateString</a>   <b>dateObject</b> </field>

类级别

对这个类中的所有日期相关的属性有效

<mapping date-format="MM-dd-yyyy HH:mm:ss">   <class-a>org.dozer.vo.TestObject</class-a>   <class-b>org.dozer.vo.TestObjectPrime</class-b>   <field>     <a>dateString</a>     <b>dateObject</b>   </field> </mapping>

全局级别

对整个文件中的所有日期相关的属性有效。

<mappings>   <configuration>     <date-format>MM/dd/yyyy HH:mm</date-format>   </configuration>    <mapping wildcard="true">     <class-a>org.dozer.vo.TestObject</class-a>     <class-b>org.dozer.vo.TestObjectPrime</class-b>     <field>       <a>dateString</a>       <b>dateObject</b>     </field>   </mapping> </mappings>

集合和数组映射(Collection and Array Mapping)
Dozer可以自动处理以下类型的双向转换。

List to List
List to Array
Array to Array
Set to Set
Set to Array
Set to List
使用hint

如果使用泛型或数组,没有必要使用hint。

如果不使用泛型或数组。在处理集合或数组之间的转换时,你需要用hint指定目标列表的数据类型。

若你不指定hint,Dozer将认为目标集合和源集合的类型是一致的。

使用Hints的范例:

<field>   <a>hintList</a>    <b>hintList</b>    <b-hint>org.dozer.vo.TheFirstSubClassPrime</b-hint>  </field> 

累计映射和非累计映射(Cumulative vs. Non-Cumulative List Mapping)

如果你要转换的目标类已经初始化,你可以选择让Dozer添加或更新对象到你的集合中。

而这取决于relationship-type配置,默认是累计。

它的设置有作用域级别:

全局级

<mappings>   <configuration>      <relationship-type>non-cumulative</relationship-type>   </configuration> </mappings>

类级别

<mappings>   <mapping relationship-type="non-cumulative">     <!-- 省略 -->     </mapping>  </mappings>

属性级别

<field relationship-type="cumulative">   <a>hintList</a>   <b>hintList</b>    <a-hint>org.dozer.vo.TheFirstSubClass</a-hint>    <b-hint>org.dozer.vo.TheFirstSubClassPrime</b-hint>  </field>

移动孤儿(Removing Orphans)

这里的孤儿是指目标集合中存在,但是源集合中不存在的元素。

你可以使用remove-orphans开关来选择是否移除这样的元素。

<field remove-orphans="true">   <a>srcList</a>    <b>destList</b>   </field>    

深度映射(Deep Mapping)
所谓深度映射,是指允许你指定属性的属性(比如一个类的属性本身也是一个类)。举例来说

Source.java

public class Source {     private long id;     private String info; }

Dest.java

public class Dest {     private long id;     private Info info; } public class Info {     private String content; }

映射规则

<mapping>   <class-a>org.zp.notes.spring.common.dozer.vo.Source</class-a>   <class-b>org.zp.notes.spring.common.dozer.vo.Dest</class-b>   <field>     <a>info</a>     <b>info.content</b>   </field> </mapping>

排除属性(Excluding Fields)
就像任何团体都有捣乱分子,类之间转换时也有想要排除的因子。

如何在做类型转换时,自动排除一些属性,Dozer提供了几种方法,这里只介绍一种比较通用的方法。

field-exclude可以排除不需要映射的属性。

<field-exclude>    <a>fieldToExclude</a>    <b>fieldToExclude</b>  </field-exclude>

单向映射(One-Way Mapping)
注:本文的映射方式,无特殊说明,都是双向映射的。

有的场景可能希望转换过程不可逆,即单向转换。

单向转换可以通过使用one-way来开启

类级别

<mapping type="one-way">    <class-a>org.dozer.vo.TestObjectFoo</class-a>   <class-b>org.dozer.vo.TestObjectFooPrime</class-b>        <field>       <a>oneFoo</a>       <b>oneFooPrime</b>     </field> </mapping>  

属性级别

<mapping>    <class-a>org.dozer.vo.TestObjectFoo2</class-a>   <class-b>org.dozer.vo.TestObjectFooPrime2</class-b>      <field type="one-way">     <a>oneFoo2</a>     <b>oneFooPrime2</b>   </field>    <field type="one-way">     <a>oneFoo3.prime</a>     <b>oneFooPrime3</b>   </field>

全局配置(Global Configuration)
全局配置用来设置全局的配置信息。此外,任何定制转换都是在这里定义的。

全局配置都是可选的。

<date-format>表示日期格式 <stop-on-errors>错误处理开关 <wildcard>通配符 <trim-strings>裁剪字符串开关 <configuration >    <date-format>MM/dd/yyyy HH:mm</date-format>   <stop-on-errors>true</stop-on-errors>   <wildcard>true</wildcard>   <trim-strings>false</trim-strings>    <custom-converters> <!-- these are always bi-directional -->     <converter type="org.dozer.converters.TestCustomConverter" >       <class-a>org.dozer.vo.TestCustomConverterObject</class-a>       <class-b>another.type.to.Associate</class-b>     </converter>    </custom-converters>      </configuration>

全局配置的作用是帮助你少配置一些参数,如果个别类的映射规则需要变更,你可以mapping中覆盖它。

覆盖的范例如下

<mapping date-format="MM-dd-yyyy HH:mm:ss">    <!-- 省略 --> </mapping>  <mapping wildcard="false">   <!-- 省略 --> </mapping>   <mapping stop-on-errors="false">    <!-- 省略 --> </mapping>  <mapping trim-strings="true">    <!-- 省略 --> </mapping>     

定制转换(Custom Converters)
如果Dozer默认的转换规则不能满足实际需要,你可以选择定制转换。

定制转换通过配置XML来告诉Dozer如何去转换两个指定的类。当Dozer转换这两个指定类的时候,会调用你的映射规则去替换标准映射规则。

为了让Dozer识别,你必须实现org.dozer.CustomConverter接口。否则,Dozer会抛异常。

具体做法:

(1) 创建一个类实现org.dozer.CustomConverter接口。

public class TestCustomConverter implements CustomConverter {    public Object convert(Object destination, Object source,        Class destClass, Class sourceClass) {     if (source == null) {       return null;     }     CustomDoubleObject dest = null;     if (source instanceof Double) {       // check to see if the object already exists       if (destination == null) {         dest = new CustomDoubleObject();       } else {         dest = (CustomDoubleObject) destination;       }       dest.setTheDouble(((Double) source).doubleValue());       return dest;     } else if (source instanceof CustomDoubleObject) {       double sourceObj =          ((CustomDoubleObject) source).getTheDouble();       return new Double(sourceObj);     } else {       throw new MappingException("Converter TestCustomConverter "           + "used incorrectly. Arguments passed in were:"           + destination + " and " + source);     }   } 

(2) 在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>     <!-- 总是双向转换的 -->     <custom-converters>       <converter type="org.dozer.converters.TestCustomConverter" >         <class-a>org.dozer.vo.CustomDoubleObject</class-a>         <class-b>java.lang.Double</class-b>       </converter>        <!-- You are responsible for mapping everything between             ClassA and ClassB -->       <converter          type="org.dozer.converters.TestCustomHashMapConverter" >         <class-a>org.dozer.vo.TestCustomConverterHashMapObject</class-a>         <class-b>org.dozer.vo.TestCustomConverterHashMapPrimeObject</class-b>       </converter>     </custom-converters>        </configuration> </mappings>

属性级

<mapping>   <class-a>org.dozer.vo.SimpleObj</class-a>   <class-b>org.dozer.vo.SimpleObjPrime2</class-b>       <field custom-converter=     "org.dozer.converters.TestCustomConverter">     <a>field1</a>     <b>field1Prime</b>   </field> </mapping>   

映射的继承(Inheritance Mapping)
Dozer支持映射规则的继承机制。

属性如果有着相同的名字则不需要在xml中配置,除非使用了hint

我们来看一个例子

<mapping>   <class-a>org.dozer.vo.SuperClass</class-a>   <class-b>org.dozer.vo.SuperClassPrime</class-b>    <field>     <a>superAttribute</a>     <b>superAttr</b>   </field> </mapping>    <mapping>   <class-a>org.dozer.vo.SubClass</class-a>   <class-b>org.dozer.vo.SubClassPrime</class-b>    <field>     <a>attribute</a>     <b>attributePrime</b>   </field> </mapping>  <mapping>   <class-a>org.dozer.vo.SubClass2</class-a>   <class-b>org.dozer.vo.SubClassPrime2</class-b>    <field>     <a>attribute2</a>     <b>attributePrime2</b>   </field> </mapping>

在上面的例子中SubClass、SubClass2是SuperClass的子类;

SubClassPrime和SubClassPrime2是SuperClassPrime的子类。

superAttribute和superAttr的映射规则会被子类所继承,所以不必再重复的在子类中去声明。

文章来源: dozer
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!