基本操作
-
创建一个
MapperFacade
MapperFacade mapperFacade = new Builder().build().getMapperFacade();
-
使用该
MapperFacade
对象进行任意的Bean转换ApproveSubmitRequest request = getRequest(); ApprovalEntry entry = mapperFacade.map(request, ApprovalEntry.class);
基本概念
MapperFactory
: 映射工厂,用来定义转换规则(任何字段映射、注册转换器、自定义映射器、用于抽象/接口类型的具体类型)并生成MapperFacade
MapperFacade
: 映射门面,进行对象转换的实际执行器
使用fluent风格的ClassMapBuilder API的声明性映射配置
基本的字段映射
转换规则是对MapperFactory
对象定义的,以下面转换的规则为例
mapperFactory.classMap(BasicPerson.class, BasicPersonDto.class)
.field("name", "fullName")
.field("age", "currentAge")
.exclude("secretKey")
.byDefault()
.register();
classMap(A, B)
方法定义了相互转换的类,不分源对象和目标对象。field("name", "fullName")
表示AB类中name
和fullName
字段的双向映射,如果只想要A对象name
赋值给B对象的fullName
,则需要使用fieldAToB("fullName", "name")
。byDefault()
方法表示当AB对象的字段名一致时,自动赋值,如果没有该方法则不会赋值。exclude("secretKey")
显示地排除了secretKey
字段的赋值。
指定要使用的特定构造函数
orika 提供了constructorA
和constructorB
方法用于使用有参构造器生成新类,例如下面的代码中在生成A对象时优先使用构造方法public BasicPerson(Long id, String name)
完成
mapperFactory.classMap(BasicPerson.class, BasicPersonDto.class)
.constructorA("id", "name")
...
.register();
数组和列表的映射元素
BasicPerson
对象中将姓名作为列表存储,第一个元素为firstName
,第二个元素为lastName
,对于列表或数组,可以使用下面的语法进行字段值的转换。
mapperFactory.classMap(BasicPerson.class, BasicPersonDto.class)
.field("nameParts[0]", "firstName")
.field("nameParts[1]", "lastName")
.register();
映射嵌套字段
嵌套属性可以使用“.”来引用,例如BasicPerson
中的姓名是一个对象private Name name
,可以使用下面语法进行字段值的转换。
mapperFactory.classMap(BasicPerson.class, BasicPersonDto.class)
.field("name.first", "firstName")
.register();
使用BoundMapperFacade以获得更好的性能
如果需要频繁进行AB对象的转换,可以使用特定的BoundMapperFacade
以追求更好的性能
MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
// 设置该facade是由ApproveSubmitRequest向ApprovalEntry转换
BoundMapperFacade<ApproveSubmitRequest, ApprovalEntry> facade = mapperFactory
.getMapperFacade(ApproveSubmitRequest.class, ApprovalEntry.class);
// 进行字段映射
ApprovalEntry entry = facade.map(request);
高级映射配置
空值映射
进行AB对象转换时,对于空值字段的处理,选择映射还是忽略根据场景的不同而不同。默认情况下orika 框架选择的策略是忽略。
ClassMap 级别
可以在ClassMap
级别设置是否映射空值,例如下面在field1
和fieldOne
转换前将其设置为“映射空值”,转换后再设置为“忽略空值”
mapperFactory.classMap(BasicPerson.class, BasicPersonDto.class)
// 设置为映射空值
.mapNulls(true).mapNullsInReverse(true)
.field("field1", "fieldOne")
// 设置为忽略空值
.mapNulls(false).mapNullsInReverse(false)
.field("field2", "fieldTwo")
.byDefault()
.register();
FieldMap 级别
在FieldMap
级别设置空值则使用fieldMap
方法,指定某些字段的转换是“赋值”还是“忽略”。
mapperFactory.classMap(BasicPerson.class, BasicPersonDto.class)
.mapNulls(false).mapNullsInReverse(false)
.fieldMap("field1", "fieldOne").mapNulls(true).mapNullsInReverse(true).add()
.field("field2", "fieldTwo")
.byDefault()
.register();
自定义单个 ClassMaps
使用 orika 框架提供的customize()
方法可以自定义由AB对象的转换方法
mapperFactory.classMap(Source.class, Destination.class)
.customize(
new CustomMapper<Source, Destination>() {
@Override
public void mapAtoB(Source source, Destination dest,
MappingContext context) {
super.mapAtoB(source, dest, context);
}
@Override
public void mapBtoA(Destination approvalEntry, Source source,
MappingContext context) {
super.mapBtoA(dest, source, context);
}
}).register();
自定义转换器
Orika 框架支持注册自定义的转换器,支持在全局注册和字段级别的注册,例如我们定义一个如下的转换器,用于从DateTime
转换到Date
public class JodaTimeToDateConverter extends CustomConverter<DateTime, Date> {
@Override
public Date convert(DateTime source, Type<? extends Date> destinationType,
MappingContext mappingContext) {
return source.toDate();
}
}
定义完转换器后支持在全局注册,如下面代码所示,应用到所有DateTime
类型字段到Date
类型字段应用转换器。
mapperFactory.getConverterFactory().registerConverter(new JodaTimeToDateConverter());
也可以在字段级别注册,如下面代码所示,仅对createTime
字段应用转换器。
mapperFactory.getConverterFactory().registerConverter("createTime", new JodaTimeToDateConverter());
另外上述仅支持了DateTime
转换到Date
,可以继承BidirectionalConverter
类以完成两个类型的双向转换,如下面代码所示
public class JodaTimeToDateConverter extends BidirectionalConverter<DateTime, Date> {
@Override
public Date convertTo(DateTime source, Type<Date> destinationType,
MappingContext mappingContext) {
return source.toDate();
}
@Override
public DateTime convertFrom(Date source, Type<DateTime> destinationType,
MappingContext mappingContext) {
return new DateTime(source);
}
}