MapStruct 是一个 Java 注释处理器,用于为 Java Bean 类生成类型安全和高性能的映射器。它使您免于手动编写映射代码,这是一项繁琐且容易出错的任务。该生成器具有合理的默认值和许多内置类型转换,也可以通过配置实现一些特殊行为。
与在运行时工作的映射框架相比,MapStruct具有以下优点:
若要在两种类型之间创建映射,请声明如下所示的映射器接口:
@Mapper
public interface CarMapper {
CarMapper INSTANCE = Mappers.getMapper( CarMapper.class );
@Mapping(target = "seatCount", source = "numberOfSeats")
CarDto carToCarDto(Car car);
}
在编译时,MapStruct将生成此接口的实现。生成的实现使用纯 Java 方法调用来映射源对象和目标对象,即不涉及反射。默认情况下,如果属性在源和目标中具有相同的名称,则会映射它们,但也可以使用一些其他注释来控制此方面和许多其他方面。
MapStruct 需要 Java 1.8 或更高版本。
对于基于 Maven 的项目,请将以下内容添加到您的 POM 文件中以使用 MapStruct(依赖项可在 Maven Central 获得):
...
<properties>
<org.mapstruct.version>1.5.5.Finalorg.mapstruct.version>
properties>
...
<dependencies>
<dependency>
<groupId>org.mapstructgroupId>
<artifactId>mapstructartifactId>
<version>${org.mapstruct.version}version>
dependency>
dependencies>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<version>3.8.1version>
<configuration>
<source>1.8source>
<target>1.8target>
<annotationProcessorPaths>
<path>
<groupId>org.mapstructgroupId>
<artifactId>mapstruct-processorartifactId>
<version>${org.mapstruct.version}version>
path>
annotationProcessorPaths>
configuration>
plugin>
plugins>
build>
...
确保至少具有 IntelliJ 2018.2.x。 在 IntelliJ 中启用注释处理(生成、执行、部署 -> 编译器 -> 注释处理器)annotationProcessors``maven-compiler-plugin
。
idea 插件(可选):MapStruct Support。
...
<properties>
<org.mapstruct.version>1.4.1.Finalorg.mapstruct.version>
properties>
...
...
<dependency>
<groupId>org.mapstructgroupId>
<artifactId>mapstructartifactId>
<version>${org.mapstruct.version}version>
dependency>
...
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<configuration>
<source>${java.version}source>
<target>${java.version}target>
<encoding>${project.build.sourceEncoding}encoding>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>${lombok.version}version>
path>
<path>
<groupId>org.projectlombokgroupId>
<artifactId>lombok-mapstruct-bindingartifactId>
<version>${lombok-mapstruct-binding.version}version>
path>
<path>
<groupId>org.mapstructgroupId>
<artifactId>mapstruct-processorartifactId>
<version>${org.mapstruct.version}version>
path>
annotationProcessorPaths>
configuration>
plugin>
plugins>
build>
...
使用注解@Mapper(componentModel = “spring”)标记接口类,编译将生成实现类;生成的实现类一般是在target目录下的对应接口类的包中。
@Mapper(componentModel = "spring")
public interface CustomerConvert {
}
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2023-05-08T19:50:07+0800",
comments = "version: 1.4.1.Final, compiler: javac, environment: Java 1.8.0_333 (Oracle Corporation)"
)
@Component
public class CustomerConvertImpl implements CustomerConvert {
}
import org.mapstruct.Mapper;
import org.mapstruct.control.DeepClone;
@Mapper(componentModel = "spring", mappingControl = DeepClone.class)
public interface Cloner {
CustomerDto clone(CustomerDto customerDto);
}
import com.cy.mapstruct.entity.CustomerDto;
import com.cy.mapstruct.entity.OrderItemDto;
import com.cy.mapstruct.entity.OrderItemKeyDto;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Generated;
import org.springframework.stereotype.Component;
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2023-05-09T20:14:48+0800",
comments = "version: 1.5.3.Final, compiler: javac, environment: Java 1.8.0_333 (Oracle Corporation)"
)
@Component
public class ClonerImpl implements Cloner {
@Override
public CustomerDto clone(CustomerDto customerDto) {
if ( customerDto == null ) {
return null;
}
CustomerDto customerDto1 = new CustomerDto();
customerDto1.setId( customerDto.getId() );
customerDto1.setCustomerName( customerDto.getCustomerName() );
customerDto1.setOrders( orderItemDtoListToOrderItemDtoList( customerDto.getOrders() ) );
customerDto1.setStock( orderItemKeyDtoOrderItemDtoMapToOrderItemKeyDtoOrderItemDtoMap( customerDto.getStock() ) );
return customerDto1;
}
protected OrderItemDto orderItemDtoToOrderItemDto(OrderItemDto orderItemDto) {
if ( orderItemDto == null ) {
return null;
}
OrderItemDto orderItemDto1 = new OrderItemDto();
orderItemDto1.setName( orderItemDto.getName() );
orderItemDto1.setQuantity( orderItemDto.getQuantity() );
return orderItemDto1;
}
protected List<OrderItemDto> orderItemDtoListToOrderItemDtoList(List<OrderItemDto> list) {
if ( list == null ) {
return null;
}
List<OrderItemDto> list1 = new ArrayList<OrderItemDto>( list.size() );
for ( OrderItemDto orderItemDto : list ) {
list1.add( orderItemDtoToOrderItemDto( orderItemDto ) );
}
return list1;
}
protected OrderItemKeyDto orderItemKeyDtoToOrderItemKeyDto(OrderItemKeyDto orderItemKeyDto) {
if ( orderItemKeyDto == null ) {
return null;
}
OrderItemKeyDto orderItemKeyDto1 = new OrderItemKeyDto();
orderItemKeyDto1.setStockNumber( orderItemKeyDto.getStockNumber() );
return orderItemKeyDto1;
}
protected Map<OrderItemKeyDto, OrderItemDto> orderItemKeyDtoOrderItemDtoMapToOrderItemKeyDtoOrderItemDtoMap(Map<OrderItemKeyDto, OrderItemDto> map) {
if ( map == null ) {
return null;
}
Map<OrderItemKeyDto, OrderItemDto> map1 = new LinkedHashMap<OrderItemKeyDto, OrderItemDto>( Math.max( (int) ( map.size() / .75f ) + 1, 16 ) );
for ( java.util.Map.Entry<OrderItemKeyDto, OrderItemDto> entry : map.entrySet() ) {
OrderItemKeyDto key = orderItemKeyDtoToOrderItemKeyDto( entry.getKey() );
OrderItemDto value = orderItemDtoToOrderItemDto( entry.getValue() );
map1.put( key, value );
}
return map1;
}
}
import com.cy.mapstruct.entity.Customer;
import com.cy.mapstruct.entity.CustomerDto;
import com.cy.mapstruct.entity.OrderItem;
import com.cy.mapstruct.entity.OrderItemDto;
import org.mapstruct.InheritInverseConfiguration;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
@Mapper(componentModel = "spring")
public interface PropConvertor {
@Mapping(source = "orders", target = "orderItems")
@Mapping(source = "customerName", target = "name")
Customer toCustomer(CustomerDto customerDto);
@InheritInverseConfiguration
CustomerDto fromCustomer(Customer customer);
OrderItem toOrder(OrderItemDto orderItemDto);
@InheritInverseConfiguration
OrderItemDto fromOrder(OrderItem orderItem);
}
import com.cy.mapstruct.entity.Customer;
import com.cy.mapstruct.entity.CustomerDto;
import com.cy.mapstruct.entity.OrderItem;
import com.cy.mapstruct.entity.OrderItemDto;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.annotation.Generated;
import org.springframework.stereotype.Component;
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2023-05-09T20:52:30+0800",
comments = "version: 1.5.3.Final, compiler: javac, environment: Java 1.8.0_333 (Oracle Corporation)"
)
@Component
public class PropConvertorImpl implements PropConvertor {
@Override
public Customer toCustomer(CustomerDto customerDto) {
if ( customerDto == null ) {
return null;
}
Customer customer = new Customer();
customer.setOrderItems( orderItemDtoListToOrderItemCollection( customerDto.getOrders() ) );
customer.setName( customerDto.getCustomerName() );
customer.setId( customerDto.getId() );
return customer;
}
@Override
public CustomerDto fromCustomer(Customer customer) {
if ( customer == null ) {
return null;
}
CustomerDto customerDto = new CustomerDto();
customerDto.setOrders( orderItemCollectionToOrderItemDtoList( customer.getOrderItems() ) );
customerDto.setCustomerName( customer.getName() );
customerDto.setId( customer.getId() );
return customerDto;
}
@Override
public OrderItem toOrder(OrderItemDto orderItemDto) {
if ( orderItemDto == null ) {
return null;
}
OrderItem orderItem = new OrderItem();
orderItem.setName( orderItemDto.getName() );
orderItem.setQuantity( orderItemDto.getQuantity() );
return orderItem;
}
@Override
public OrderItemDto fromOrder(OrderItem orderItem) {
if ( orderItem == null ) {
return null;
}
OrderItemDto orderItemDto = new OrderItemDto();
orderItemDto.setName( orderItem.getName() );
orderItemDto.setQuantity( orderItem.getQuantity() );
return orderItemDto;
}
protected Collection<OrderItem> orderItemDtoListToOrderItemCollection(List<OrderItemDto> list) {
if ( list == null ) {
return null;
}
Collection<OrderItem> collection = new ArrayList<OrderItem>( list.size() );
for ( OrderItemDto orderItemDto : list ) {
collection.add( toOrder( orderItemDto ) );
}
return collection;
}
protected List<OrderItemDto> orderItemCollectionToOrderItemDtoList(Collection<OrderItem> collection) {
if ( collection == null ) {
return null;
}
List<OrderItemDto> list = new ArrayList<OrderItemDto>( collection.size() );
for ( OrderItem orderItem : collection ) {
list.add( fromOrder( orderItem ) );
}
return list;
}
}
import com.cy.mapstruct.entity.OrderItem;
import com.cy.mapstruct.entity.OrderItemDto;
import org.mapstruct.InheritInverseConfiguration;
import org.mapstruct.Mapper;
import java.util.List;
@Mapper(componentModel = "spring")
public interface ListConvertor {
List<OrderItem> toOrders(List<OrderItemDto> orderItemDtos);
@InheritInverseConfiguration
List<OrderItemDto> fromOrders(List<OrderItem> orderItems);
}
import com.cy.mapstruct.entity.OrderItem;
import com.cy.mapstruct.entity.OrderItemDto;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Generated;
import org.springframework.stereotype.Component;
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2023-05-12T20:55:39+0800",
comments = "version: 1.5.3.Final, compiler: javac, environment: Java 1.8.0_333 (Oracle Corporation)"
)
@Component
public class ListConvertorImpl implements ListConvertor {
@Override
public List<OrderItem> toOrders(List<OrderItemDto> orderItemDtos) {
if ( orderItemDtos == null ) {
return null;
}
List<OrderItem> list = new ArrayList<OrderItem>( orderItemDtos.size() );
for ( OrderItemDto orderItemDto : orderItemDtos ) {
list.add( orderItemDtoToOrderItem( orderItemDto ) );
}
return list;
}
@Override
public List<OrderItemDto> fromOrders(List<OrderItem> orderItems) {
if ( orderItems == null ) {
return null;
}
List<OrderItemDto> list = new ArrayList<OrderItemDto>( orderItems.size() );
for ( OrderItem orderItem : orderItems ) {
list.add( orderItemToOrderItemDto( orderItem ) );
}
return list;
}
protected OrderItem orderItemDtoToOrderItem(OrderItemDto orderItemDto) {
if ( orderItemDto == null ) {
return null;
}
OrderItem orderItem = new OrderItem();
orderItem.setName( orderItemDto.getName() );
orderItem.setQuantity( orderItemDto.getQuantity() );
return orderItem;
}
protected OrderItemDto orderItemToOrderItemDto(OrderItem orderItem) {
if ( orderItem == null ) {
return null;
}
OrderItemDto orderItemDto = new OrderItemDto();
orderItemDto.setName( orderItem.getName() );
orderItemDto.setQuantity( orderItem.getQuantity() );
return orderItemDto;
}
}
import com.cy.mapstruct.entity.Customer;
import com.cy.mapstruct.entity.CustomerDto;
import org.mapstruct.InheritInverseConfiguration;
import org.mapstruct.IterableMapping;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.Named;
import org.mapstruct.Qualifier;
import java.util.List;
@Mapper(componentModel = "spring")
public interface ListChildrenConvertor {
@IterableMapping(qualifiedByName = "toCustomer")
List<Customer> toCustomers(List<CustomerDto> customerDtos);
@Named("toCustomer")
@Mappings({
@Mapping(source = "orders", target = "orderItems"),
@Mapping(source = "customerName", target = "name"),
})
Customer toCustomer(CustomerDto customerDto);
}
import com.cy.mapstruct.entity.Customer;
import com.cy.mapstruct.entity.CustomerDto;
import com.cy.mapstruct.entity.OrderItem;
import com.cy.mapstruct.entity.OrderItemDto;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.annotation.Generated;
import org.springframework.stereotype.Component;
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2023-05-12T21:05:27+0800",
comments = "version: 1.5.3.Final, compiler: javac, environment: Java 1.8.0_333 (Oracle Corporation)"
)
@Component
public class ListChildrenConvertorImpl implements ListChildrenConvertor {
@Override
public List<Customer> toCustomers(List<CustomerDto> customerDtos) {
if ( customerDtos == null ) {
return null;
}
List<Customer> list = new ArrayList<Customer>( customerDtos.size() );
for ( CustomerDto customerDto : customerDtos ) {
list.add( toCustomer( customerDto ) );
}
return list;
}
@Override
public Customer toCustomer(CustomerDto customerDto) {
if ( customerDto == null ) {
return null;
}
Customer customer = new Customer();
customer.setOrderItems( orderItemDtoListToOrderItemCollection( customerDto.getOrders() ) );
customer.setName( customerDto.getCustomerName() );
customer.setId( customerDto.getId() );
return customer;
}
protected OrderItem orderItemDtoToOrderItem(OrderItemDto orderItemDto) {
if ( orderItemDto == null ) {
return null;
}
OrderItem orderItem = new OrderItem();
orderItem.setName( orderItemDto.getName() );
orderItem.setQuantity( orderItemDto.getQuantity() );
return orderItem;
}
protected Collection<OrderItem> orderItemDtoListToOrderItemCollection(List<OrderItemDto> list) {
if ( list == null ) {
return null;
}
Collection<OrderItem> collection = new ArrayList<OrderItem>( list.size() );
for ( OrderItemDto orderItemDto : list ) {
collection.add( orderItemDtoToOrderItem( orderItemDto ) );
}
return collection;
}
}
注解 | 描述 |
---|---|
@Mapper | 指示此接口将用于生成映射实现 |
@Mapping | 将源和目标属性之间的映射指定为参数 |
@Mappings | 允许使用多个 @Mapping 注释指定映射 |
@InheritConfiguration | 继承父映射配置 |
@BeanMapping | 自定义要应用于映射器方法的 Bean 映射选项 |
@BeforeMapping | 在映射开始时执行方法 |
@AfterMapping | 在映射结束时执行方法 |
@IterableMapping | 将迭代器类型映射指定为参数 |
@ValueMapping | 为枚举类型或其他可枚举类型提供自定义值映射 |
@Named | 为参数提供一个自定义名称 |
@Context | 将用户提供的上下文参数注入 Mapper 方法 |
@AfterMappingConversion | 在映射后进行类型转换 |
@Qualifier | 为不同的 Mapper 或 Mapping 提供自定义限定符 |
@MapperDependency | 指定该 Mapper 接口依赖于另一个 Mapper 接口 |
public interface PersonMapper {
PersonDto personToPersonDto(Person person);
List<PersonDto> personsToPersonDtos(List<Person> persons);
}
public interface PersonMapper {
@Mapping(source = "firstName", target = "name")
PersonDto personToPersonDto(Person person);
}
public interface PersonMapper {
@Mappings({
@Mapping(source = "firstName", target = "name"),
@Mapping(source = "age", target = "ageGroup")
})
PersonDto personToPersonDto(Person person);
}
@Mapper(config = ParentMapper.class)
public interface ChildMapper {
@InheritConfiguration
ChildDto childToChildDto(Child child);
}
public interface PersonMapper {
@BeanMapping(ignoreByDefault = true)
@Mapping(source = "firstName", target = "name")
PersonDto personToPersonDto(Person person);
}
public interface PersonMapper {
@BeforeMapping
default void beforePersonToPersonDto(Person person, @MappingTarget PersonDto personDto) {
// do something before mapping
}
PersonDto personToPersonDto(Person person);
}
public interface PersonMapper {
@AfterMapping
default void afterPersonToPersonDto(Person person, @MappingTarget PersonDto personDto) {
// do something after mapping
}
PersonDto personToPersonDto(Person person);
}
public interface PersonMapper {
@IterableMapping(dateFormat = "yyyy-MM-dd")
List<String> datesToStrings(List<Date> dates);
}
public interface ColorMapper {
@ValueMapping(source = "RED", target = "0")
@ValueMapping(source = "GREEN", target = "1")
@ValueMapping(source = "BLUE", target = "2")
int colorToInt(Color color);
}
public interface PersonMapper {
PersonDto personToPersonDto(@Named("firstName") String name, @Named("old") int age);
}
public interface PersonMapper {
PersonDto personToPersonDto(Person person, @Context SecurityContext securityContext);
}
public interface HumanMapper {
@AfterMappingConversion
default void afterPersonToPersonDtoConversion(Date birthDate, @MappingTarget HumanDto humanDto) {
humanDto.setAge(getAge(birthDate));
}
default int getAge(Date birthDate) {
// calculate age
return 0;
}
HumanDto humanToHumanDto(Human human);
}
@Mapper(qualifier = "Child")
public interface PersonMapper {
PersonDto personToPersonDto(Person person);
}
@Mapper(uses = {ParentMapper.class})
public interface ChildMapper {
ChildDto childToChildDto(Child child);
}
使用 MapStruct 的这些注解,可以很方便地进行 Java Bean 的映射。
主页
源代码
示例
问题跟踪器