1. 概述
MapStruct 是一个Java Bean 映射器。本文我们将学习如何在MapStruct中实现局部映射,忽略某些不需要的字段。
2. MapStruct基础用法
首先我们回顾下MapStruct的基础用法。
假设我们有两个Java Bean: Car 和 CarDTO 需要转换
public class CarDTO {
private int id;
private String name;
}
public class Car {
private int id;
private String name;
}
首先我们需要定义一个mapper接口,MapStruct 在编译过程中会扫描 Java 注解,自动生成映射器的实现:
@Mapper
public interface CarMapper {
CarMapper INSTANCE = Mappers.getMapper(CarMapper.class);
CarDTO carToCarDTO(Car car);
}
转换测试:
@Test
public void givenCarEntitytoCar_whenMaps_thenCorrect() {
Car entity = new Car();
entity.setId(1);
entity.setName("Toyota");
// Car 转 CarDTO
CarDTO carDto = CarMapper.INSTANCE.carToCarDTO(entity);
assertThat(carDto.getId()).isEqualTo(entity.getId());
assertThat(carDto.getName()).isEqualTo(entity.getName());
}
3. 未映射的属性
由于 MapStruct 在编译时运行,因此它比其他动态映射框架要更快。
同时,如果映射不完整,即有的源属性在目标属性中不存在时,Mapstruct还会在编译时发出警告:
Warning:(X,X) java: Unmapped target property: "propertyName".
如果确实是马虎遗漏了,这个警告还是非常有用的。但实际情况我们就是不需要映射一些字段怎么办呢,例如下面的例子
public class DocumentDTO {
private int id;
private String title;
private String text;
private List<String> comments;
private String author;
}
public class Document {
private int id;
private String title;
private String text;
private Date modificationTime;
}
DocumentMapper定义:
@Mapper
public interface DocumentMapper {
DocumentMapper INSTANCE = Mappers.getMapper(DocumentMapper.class);
DocumentDTO documentToDocumentDTO(Document entity);
Document documentDTOToDocument(DocumentDTO dto);
}
我们不希望映射的字段:
- DocumentDTO 中的 comments
- DocumentDTO 中的 author
- Document 中的 modificationTime
默认配置下MapStruct在编译时会提示 Unmapped Warning,下面我们讲解如何解决该问题
4. 忽略指定字段
方法一,通过 @Mapping 注解的 ignore 参数忽略指定字段:
@Mapper
public interface DocumentMapperMappingIgnore {
DocumentMapperMappingIgnore INSTANCE =
Mappers.getMapper(DocumentMapperMappingIgnore.class);
@Mapping(target = "comments", ignore = true)
@Mapping(target = "author", ignore = true)
DocumentDTO documentToDocumentDTO(Document entity);
@Mapping(target = "modificationTime", ignore = true)
Document documentDTOToDocument(DocumentDTO dto);
}
该方法简单明了,但字段比较多的时候就显得繁琐难用了。
5. 配置映射策略
对于 unmapped 的字段,MapStruct 有3种错误级别:
- ERROR: 错误,会直接导致构建失败
- WARN: 警告(默认),不会失败但会打印警告
- IGNORE: 忽略,不会有任何错误输出
所以,为了忽略警告,可以通过给 unmappedTargetPolicy 设置 IGNORE 实现。
5.1. 每个Mapper设置单独的策略
@Mapper(unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface DocumentMapperUnmappedPolicy {
// mapper methods
}
5.2. 共享 MapperConfig
首先定义一个共享的配置接口
@MapperConfig(unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface IgnoreUnmappedMapperConfig {
}
然后应用配置:
@Mapper(config = IgnoreUnmappedMapperConfig.class)
public interface DocumentMapperWithConfig {
// mapper methods
}
注意,这是一个最简单的@MapperConfig使用例子,似乎并不比在每个映射器上设置策略好多少。当配置项多了的时候,共享配置就变得非常有用。
5.3. 通过mvn配置
方法三,我们也可以直接在 mvn 插件中通过compilerArgs参数进行全局配置
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</path>
</annotationProcessorPaths>
<compilerArgs>
<compilerArg>
-Amapstruct.unmappedTargetPolicy=IGNORE
</compilerArg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
6. 优先顺序
本文我们介绍了4种方式用于解决部分映射导致的警告问题。根据实际场景可以独立使用,也可组合使用。
对于大型项目,一般会包含大量的 bean 和 mapper。通常情况下,我们不希望允许部分映射。 随着时间推移,往bean中新增字段时难免忘记同步而未被察觉到。
因此,通过 Maven 配置添加一个全局设置,以便在出现部分映射时让构建失败,可能是个不错的主意。
对于希望屏蔽的错误,我们可以覆盖全局行为。其优先级顺序如下(从高到低):
- 在映射方法级别忽略特定字段
- 映射器上的策略
- 共享的 MapperConfig
- 全局配置
7. 总结
本文我们介绍了几种解决 MapStruct 中 Unmapped target property 警告的方法。
最后,文中的示例代码可从GitHub上获取。