MapStruct使用说明
1、简介
MapStruct是一个Java注释处理器,用于生成类型安全的bean映射类。
您要做的就是定义一个映射器接口,该接口声明任何必需的映射方法。在编译期间,MapStruct将生成此接口的实现。此实现使用简单的Java方法调用在源对象和目标对象之间进行映射,即没有反射或类似内容。
与手动编写映射代码相比,MapStruct通过生成繁琐且易于出错的代码来节省时间。遵循配置方法上的约定,MapStruct使用合理的默认值,但在配置或实现特殊行为时不加理会。
2、构建
2.1、Apache Maven
在 pom.xml 文件中,加入如下配置
...
<properties>
<org.mapstruct.version>1.5.3.Final</org.mapstruct.version>
</properties>
...
<dependencies>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
</dependencies>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
...
3、定义映射器
3.1、基本映射器
如果目标对象与源对象属性不一致,则需要明确指定属性名
@Mapper
public interface CarMapper {
@Mapping(target = "manufacturer", source = "make")
@Mapping(target = "seatCount", source = "numberOfSeats")
CarDto carToCarDto(Car car);
@Mapping(target = "fullName", source = "name")
PersonDto personToPersonDto(Person person);
}
3.2、表达式
指定目标对象使用指定表达式赋值
@Mapping(target = "creationDate", expression = "java(new java.util.Date())")
3.3、自定义方法
如果复制对象内部有引用类型的成员,可自定义方法,完成引用类型之间的对应拷贝。
@Mapper
public interface CarMapper {
@Mapping(...)
...
CarDto carToCarDto(Car car);
default PersonDto personToPersonDto(Person person) {
//hand-written mapping logic
}
}
3.4、多个源对象
3.4.1、源数据来源多个对象
@Mapper
public interface AddressMapper {
@Mapping(target = "description", source = "person.description")
@Mapping(target = "houseNumber", source = "address.houseNo")
DeliveryAddressDto personAndAddressToDeliveryAddressDto(Person person, Address address);
}
3.4.2、源数据来源普通参数
@Mapper
public interface AddressMapper {
@Mapping(target = "description", source = "person.description")
@Mapping(target = "houseNumber", source = "hn")
DeliveryAddressDto personAndAddressToDeliveryAddressDto(Person person, Integer hn);
}
3.5、嵌套对象属性
如果复制对象内部有相同的引用类型,指定成员属性名,可直接复制。如果不同,则需要明确指定成员变量的某个属性,对应另一个对象的某个成员属性的某个属性。
@Mapper
public interface CustomerMapper {
@Mapping( target = "name", source = "record.name" )
@Mapping( target = ".", source = "record" )
@Mapping( target = ".", source = "account" )
Customer customerDtoToCustomer(CustomerDto customerDto);
}
3.6、更新bean实例
通过 @MappingTarget 注解,更新实例。
@Mapper
public interface CarMapper {
void updateCarFromDto(CarDto carDto, @MappingTarget Car car);
}
3.7、public访问权限修饰符修饰的成员
public class Customer {
private Long id;
private String name;
//getters and setter omitted for brevity
}
public class CustomerDto {
public Long id;
public String customerName;
}
@Mapper
public interface CustomerMapper {
CustomerMapper INSTANCE = Mappers.getMapper( CustomerMapper.class );
@Mapping(target = "name", source = "customerName")
Customer toCustomer(CustomerDto customerDto);
@InheritInverseConfiguration
CustomerDto fromCustomer(Customer customer);
}
3.8、生成器
略。
3.9、构造器
MapStruct 支持使用构造函数来映射目标类型。执行映射时,MapStruct 会检查所映射的类型是否有构建器。如果没有构建器,则 MapStruct 会查找单个可访问的构造函数。当有多个构造函数时,执行以下操作来选择应该使用的构造函数:
- 如果构造函数使用名为 @Default 的注释进行批注,则将使用该批注。
- 如果存在单个公共构造函数,则将使用该构造函数构造对象,而忽略其他非公共构造函数。
- 如果存在无参数构造函数,则它将用于构造对象,其他构造函数将被忽略。
- 如果有多个符合条件的构造函数,则由于构造函数不明确,将出现编译错误。为了打破歧义,可以使用名为 @Default 的注释
3.10、映射Map到Bean
指定Map的key映射到对应Bean的属性。
public class Customer {
private Long id;
private String name;
//getters and setter omitted for brevity
}
@Mapper
public interface CustomerMapper {
// 此时map对象中包括键customerName
@Mapping(target = "name", source = "customerName")
Customer toCustomer(Map<String, String> map);
}
4、获取映射器示例
4.1、通过映射工厂获取实例
CarMapper mapper = Mappers.getMapper( CarMapper.class );
5、数据类型转化
5.1、隐式类型转化
8种基本类型与其包装类,可以自动转化。
8种基本类型与String,可以自动转化。
5.1.1、数字格式化
@Mapper
public interface CarMapper {
@Mapping(source = "price", numberFormat = "$#.00")
CarDto carToCarDto(Car car);
@IterableMapping(numberFormat = "$#.00")
List<String> prices(List<Integer> prices);
}
5.1.2、日期格式化
@Mapper
public interface CarMapper {
@Mapping(source = "manufacturingDate", dateFormat = "dd.MM.yyyy")
CarDto carToCarDto(Car car);
@IterableMapping(dateFormat = "dd.MM.yyyy")
List<String> stringListToDateList(List<Date> dates);
}
5.2、引用类型映射
明确指定属性即可完成复制。
5.3、嵌套类型映射
通过明确指定的属性值,完成复制。
5.4、自定义映射方法
略。
5.5、调用其他映射器
定义公用映射器
public class DateMapper {
public String asString(Date date) {
return date != null ? new SimpleDateFormat( "yyyy-MM-dd" ).format( date ) : null;
}
public Date asDate(String date) {
try {
return date != null ? new SimpleDateFormat( "yyyy-MM-dd" ).parse( date ) : null;
} catch ( ParseException e ) {
throw new RuntimeException( e );
}
}
}
使用
@Mapper(uses=DateMapper.class)
public interface CarMapper {
CarDto carToCarDto(Car car);
}
5.6、将映射目标类型传递给自定义映射器
略。
5.7、将上下文或状态对象传递给自定义方法
5.8、映射方法解析
使用 @Mapper#uses() 可重用映射器
5.9、限定符
使用限定符指定的类生成值
5.10、限定符结合默认值
使用限定符指定生成默认值方法
@Mapper
public interface MovieMapper {
@Mapping( target = "category", qualifiedByName = "CategoryToString", defaultValue = "DEFAULT" )
GermanRelease toGerman( OriginalRelease movies );
@Named("CategoryToString")
default String defaultValueForQualifier(Category cat) {
// some mapping logic
}
}
此时 category 为空时,将使用 defaultValueForQualifier 方法生成默认值。
6、映射集合
7、映射流
8、映射值
9、对象工厂
10、高级映射配置
11、映射配置重用
12、自定义映射
13、SPI
14、第三方集成
薔薇猛虎皆成個性,陽光雨露俱是天恩!