- @Mapper(mappingControl = DeepClone.class)//这里需要注意用这个注解
- public interface Cloner {
- Cloner MAPPER = Mappers.getMapper( Cloner.class );
- CustomerDto clone(CustomerDto customerDto);
- }
这个注解的作用是当有重复的转换类时,指定一个,但也可以用注解来实现,下面的例子就是从一个集合中的对象中特定的地方取值然后mapping到特定的属性上,下面是一个集合应用。
- public class Source {
- private List<Integer> myIntegers;
- private List<String> myStrings;
- }
- public class Target {
- private Integer myInteger;
- private String myString;
- }
- public static void main( String[] args ) {
- Source s = new Source();
- s.setMyIntegers( Arrays.asList( 5, 3, 7 ) );
- s.setMyStrings( Arrays.asList( "five", "three", "seven " ) );
-
- Target t = SourceTargetMapper.MAPPER.toTarget( s );
- System.out.println( t.getMyInteger() );
- System.out.println( t.getMyString() );
- }
- //5
- //seven
- @Mapper( uses = IterableNonInterableUtil.class )
- public interface SourceTargetMapper {
- SourceTargetMapper MAPPER = Mappers.getMapper( SourceTargetMapper.class );
- @Mapping( source = "myIntegers", target = "myInteger", qualifiedBy = FirstElement.class )
- @Mapping( source = "myStrings", target = "myString", qualifiedBy = LastElement.class )
- Target toTarget( Source s );
- }
-
- @Qualifier
- @Target(ElementType.METHOD)
- @Retention(RetentionPolicy.SOURCE)
- public @interface FirstElement {
- }
-
- @Qualifier
- @Target(ElementType.METHOD)
- @Retention(RetentionPolicy.SOURCE)
- public @interface LastElement {
- }
- public class IterableNonInterableUtil {
-
- @FirstElement
- public <T> T first( List<T> in ) {
- if ( in != null && !in.isEmpty() ) {
- return in.get( 0 );
- }
- else {
- return null;
- }
- }
-
- @LastElement
- public <T> T last( List<T> in ) {
- if ( in != null && !in.isEmpty() ) {
- return in.get( in.size() - 1 );
- }
- else {
- return null;
- }
- }
- }
- @Mapper
- public interface SourceTargetMapper {
-
- SourceTargetMapper MAPPER = Mappers.getMapper( SourceTargetMapper.class );
-
- @Mapping( target = "descriptionArticle1", source = "brush.description" )
- @Mapping( target = "descriptionArticle2", source = "paste.description" )
- CombinedOfferingEntity toEntity(Toothbrush brush, ToothPaste paste, @Context ArticleRepository repo);
-
- @ObjectFactory
- default <T extends Entity> T lookup(Toothbrush brush, ToothPaste paste, @Context ArticleRepository repo,
- @TargetType Class<T> targetType ) {
- ComposedKey key = new ComposedKey(brush.getName(), paste.getName() );
- CombinedOfferingEntity entity = repo.lookup( key );
- if ( entity == null ) {
- entity = new CombinedOfferingEntity();
- }
- return (T) entity;
- }
- }
-
- //生成的代码如下,上面代码大概的逻辑是先执行工厂方法,然后先执行工厂方法,再执行余下的映射
- public CombinedOfferingEntity toEntity(Toothbrush brush, ToothPaste paste, ArticleRepository repo) {
- if ( brush == null && paste == null ) {
- return null;
- }
-
- CombinedOfferingEntity combinedOfferingEntity = lookup( brush, paste, repo, CombinedOfferingEntity.class );
-
- if ( brush != null ) {
- combinedOfferingEntity.setDescriptionArticle1( brush.getDescription() );
- }
- if ( paste != null ) {
- combinedOfferingEntity.setDescriptionArticle2( paste.getDescription() );
- }
-
- return combinedOfferingEntity;
- }
- public class Employee {
- private String name;
- private Employee reportsTo;
- private List
team; - }
- public class EmployeeDto {
- private String employeeName;
- private EmployeeDto reportsTo;
- private List
team; - }
- @Mapper
- public interface EmployeeMapper {
-
- EmployeeMapper MAPPER = Mappers.getMapper( EmployeeMapper.class );
-
- @Mapping(source = "employeeName", target = "name")
- Employee toEmployee(EmployeeDto employeeDto, @Context CycleAvoidingMappingContext context);
-
- @InheritInverseConfiguration
- EmployeeDto fromEmployee(Employee employee, @Context CycleAvoidingMappingContext context);
- }
- public class CycleAvoidingMappingContext {
- private Map<Object, Object> knownInstances = new IdentityHashMap<Object, Object>();
-
- @BeforeMapping
- public
T getMappedInstance(Object source, @TargetType Class targetType ) { - return (T) knownInstances.get( source );
- }
-
- @BeforeMapping
- public void storeMappedInstance(Object source, @MappingTarget Object target) {
- knownInstances.put( source, target );
- }
- }
- public class Source {
- private Map<String, Object> map;
- }
- public class Target {
- private String ip;
- private String server;
- }
-
- @Mapper( uses = MappingUtil.class )
- public interface SourceTargetMapper {
-
- SourceTargetMapper MAPPER = Mappers.getMapper( SourceTargetMapper.class );
-
- @Mapping(source = "map", target = "ip", qualifiedBy = Ip.class )
- @Mapping(source = "map", target = "server", qualifiedBy = Server.class )
- Target toTarget(Source s);
- }
-
- public class MappingUtil {
-
- @Qualifier
- @Target(ElementType.METHOD)
- @Retention(RetentionPolicy.SOURCE)
- public @interface Ip {
- }
-
- @Qualifier
- @Target(ElementType.METHOD)
- @Retention(RetentionPolicy.SOURCE)
- public static @interface Server {
- }
-
- @Ip
- public String ip(Map<String, Object> in) {
- return (String) in.get("ip");
- }
-
- @Server
- public String server(Map<String, Object> in) {
- return (String) in.get("server");
- }
- }
-
- @Test
- public void testMapperOnExistingIpAndServer() {
-
- Map<String, Object> map = new HashMap<>();
- map.put("ip", "127.0.0.1");
- map.put("server", "168.192.1.1");
-
- Source s = new Source(map);
- Target t = SourceTargetMapper.MAPPER.toTarget( s );
- System.out.println(JSONUtil.toJsonStr(t));
- //{"server":"168.192.1.1","ip":"127.0.0.1"}
- }
- //下面的例子是从map中映射字段到object
- public class Employee {
-
- private String id;
- private String name;
- private Department department;
- }
- public class Department {
- private String id;
- private String name;
- }
-
- @Mapper
- public interface MapToBeanMapper {
-
- MapToBeanMapper INSTANCE = Mappers.getMapper(MapToBeanMapper.class);
-
- @Mapping(target = "department", ignore = true)
- Employee fromMap(Map<String, String> map);
-
- @AfterMapping
- default void finishEmployee(@MappingTarget Employee employee, Map<String, String> map) {
- employee.setDepartment(fromMapToDepartment(map));
- }
-
- @Mapping(target = "id", source = "did")
- @Mapping(target = "name", source = "dname")
- Department fromMapToDepartment(Map<String, String> map);
- }
-
- @Test
- public void shouldMapMapToBean() {
- Map<String, String> map = new HashMap<>();
- map.put("id", "1234");
- map.put("name", "Tester");
- map.put("did", "4321"); //Department Id
- map.put("dname", "Test");// Depart name
-
- Employee employee = MapToBeanMapper.INSTANCE.fromMap(map);
- }
- //主要是用于一些特定的规则处理
- step-1:
- public class CustomAccessorNamingStrategy extends DefaultAccessorNamingStrategy {
-
- @Override
- public boolean isGetterMethod(ExecutableElement method) {
- String methodName = method.getSimpleName().toString();
- return !methodName.startsWith( "with" ) && method.getReturnType().getKind() != TypeKind.VOID;
- }
-
- @Override
- public boolean isSetterMethod(ExecutableElement method) {
- String methodName = method.getSimpleName().toString();
- return methodName.startsWith( "with" ) && methodName.length() > 4;
- }
-
- @Override
- public String getPropertyName(ExecutableElement getterOrSetterMethod) {
- String methodName = getterOrSetterMethod.getSimpleName().toString();
- return Introspector.decapitalize( methodName.startsWith( "with" ) ? methodName.substring( 4 ) : methodName );
- }
- }
- step-2
- 在 resources/META-INF.services目录下新建文件
- org.mapstruct.example.spi.CustomAccessorNamingStrategy
- 文件内容
- org.mapstruct.example.spi.CustomAccessorNamingStrategy
- 这主要是配置,以指定comiple的顺序
- <!--处理lombok和mapstruft 加载顺序的问题 防止在生成的实体没有属性-->
- <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.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- <version>${lombok.version}</version> //1.18.20 || 1.18.20
- </path>
- <path>
- <groupId>org.mapstruct</groupId>
- <artifactId>mapstruct-processor</artifactId>
- <version>${mapstruct.version}</version> //1.4.2.Final || 1.5.0.Beta2
- </path>
-
- <!-- additional annotation processor required as of Lombok 1.18.16 -->
- <path>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok-mapstruct-binding</artifactId>
- <version>0.1.0</version> //0.1.0 || 0.2.0
- </path>
- </annotationProcessorPaths>
- </configuration>
- </plugin>
- </plugins>