Dozer 应用指南

这篇文章是本人在阅读 Dozer 官方文档(5.5.1 版本,官网已经一年多没更新了)的过程中,整理下来我认为比较基础的应用场景。

本文中提到的例子应该能覆盖 JavaBean 映射的大部分场景,希望对你有所帮助。

简介

Dozer 是什么?

Dozer 是一个 JavaBean 映射工具库。

它支持简单的属性映射,复杂类型映射,双向映射,隐式显式的映射,以及递归映射。

它支持三种映射方式:注解、API、XML。

它是开源的,遵从Apache 2.0 协议

安装

引入 jar 包

maven 方式

如果你的项目使用 maven,添加以下依赖到你的 pom.xml 即可:

非 maven 方式

如果你的项目不使用 maven,那就只能发扬不怕苦不怕累的精神了。

使用 Dozer 需要引入 Dozer 的 jar 包以及其依赖的第三方 jar 包。

Eclipse 插件

Dozer 有插件可以在 Eclipse 中使用(不知道是否好用,反正我没用过)

插件地址: http://dozer.sourceforge.net/eclipse-plugin

使用

将 Dozer 引入到工程中后,我们就可以来小试一番了。

实践出真知,先以一个最简单的例子来展示 Dozer 映射的处理过程。

准备

我们先准备两个要互相映射的类

NotSameAttributeA.java

NotSameAttributeB.java

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

Dozer 的配置

为什么要有映射配置?

如果要映射的两个对象有完全相同的属性名,那么一切都很简单。

只需要直接使用 Dozer 的 API 即可:

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

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

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

映射配置文件

src/test/resources目录下添加dozer/dozer-mapping.xml文件。 <mapping>标签中允许你定义<class-a><class-b>,对应着相互映射的类。 <field>标签里定义要映射的特殊属性。需要注意<a><class-a>对应,<b><class-b>对应,聪明的你,猜也猜出来了吧。

与 Spring 整合

配置 DozerBeanMapperFactoryBean

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

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

spring-dozer.xml 文件范例

自动装配

至此,万事具备,你只需要自动装配mapper

运行一下单元测试,绿灯通过。

Dozer 支持的数据类型转换

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 的映射流程。但是两个类进行映射,有很多复杂的情况,相应的,你也需要一些更复杂的配置。

Dozer 有三种映射配置方式:

  • 注解方式

  • API 方式

  • XML 方式

用注解来配置映射

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

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

让我们来试试吧:

TargetBean.java

TargetBean.java

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

测试一下,绿灯通过。

官方文档说,虽然当前版本(文档的版本对应 Dozer 5.5.1)仅支持@Mapping,但是在未来的发布版本会提供其他的注解功能,那就敬请期待吧(再次吐槽一下:一年多没更新了)。

用 API 来配置映射

个人觉得这种方式比较麻烦,不推荐,也不想多做介绍,就是这么任性。

用 XML 来配置映射

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

属性名不同时的映射(Basic Property Mapping)

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

字符串和日期映射(String to Date Mapping)

字符串在和日期进行映射时,允许用户指定日期的格式。

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

属性级别

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

类级别

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

全局级别

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

集合和数组映射(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 的范例:

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

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

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

它的设置有作用域级别:

  • 全局级

  • 类级别

  • 属性级别

移动孤儿(Removing Orphans)

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

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

深度映射(Deep Mapping)

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

Source.java

Dest.java

映射规则

排除属性(Excluding Fields)

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

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

更多详情参考官网

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

单向映射(One-Way Mapping)

注:本文的映射方式,无特殊说明,都是双向映射的。

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

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

类级别

属性级别

全局配置(Global Configuration)

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

全局配置都是可选的。

  • <date-format>表示日期格式

  • <stop-on-errors>错误处理开关

  • <wildcard>通配符

  • <trim-strings>裁剪字符串开关

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

覆盖的范例如下

定制转换(Custom Converters)

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

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

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

具体做法:

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

(2) 在 xml 中引用定制的映射规则

引用定制的映射规则也是分级的,你可以酌情使用。

  • 全局级

  • 属性级

映射的继承(Inheritance Mapping)

Dozer 支持映射规则的继承机制。

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

我们来看一个例子

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

SubClassPrime 和 SubClassPrime2 是 SuperClassPrime 的子类。

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

参考

Dozer 官方文档 | Dozer 源码地址

Last updated

Was this helpful?