一、clone
mappingControl = DeepClone.class)//这里需要注意用这个注解
public interface Cloner {
Cloner MAPPER = Mappers.getMapper( Cloner.class );
CustomerDto clone(CustomerDto customerDto);
}
(
二、特殊注解
2.1、@qualifiedBy
这个注解的作用是当有重复的转换类时,指定一个,但也可以用注解来实现,下面的例子就是从一个集合中的对象中特定的地方取值然后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
uses = IterableNonInterableUtil.class )
public interface SourceTargetMapper {
SourceTargetMapper MAPPER = Mappers.getMapper( SourceTargetMapper.class );
( source = "myIntegers", target = "myInteger", qualifiedBy = FirstElement.class )
( source = "myStrings", target = "myString", qualifiedBy = LastElement.class )
Target toTarget( Source s );
}
(ElementType.METHOD)
(RetentionPolicy.SOURCE)
public @interface FirstElement {
}
(ElementType.METHOD)
(RetentionPolicy.SOURCE)
public @interface LastElement {
}
(
public class IterableNonInterableUtil {
public <T> T first( List<T> in ) {
if ( in != null && !in.isEmpty() ) {
return in.get( 0 );
}
else {
return null;
}
}
public <T> T last( List<T> in ) {
if ( in != null && !in.isEmpty() ) {
return in.get( in.size() - 1 );
}
else {
return null;
}
}
}
2.2、@ObjectFactory
public interface SourceTargetMapper {
SourceTargetMapper MAPPER = Mappers.getMapper( SourceTargetMapper.class );
( target = "descriptionArticle1", source = "brush.description" )
( target = "descriptionArticle2", source = "paste.description" )
CombinedOfferingEntity toEntity(Toothbrush brush, ToothPaste paste, ArticleRepository repo);
default <T extends Entity> T lookup(Toothbrush brush, ToothPaste paste, ArticleRepository repo,
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;
}
2.3、@Context循环依赖
public class Employee {
private String name;
private Employee reportsTo;
private List<Employee> team;
}
public class EmployeeDto {
private String employeeName;
private EmployeeDto reportsTo;
private List<EmployeeDto> team;
}
public interface EmployeeMapper {
EmployeeMapper MAPPER = Mappers.getMapper( EmployeeMapper.class );
(source = "employeeName", target = "name")
Employee toEmployee(EmployeeDto employeeDto, CycleAvoidingMappingContext context);
EmployeeDto fromEmployee(Employee employee, CycleAvoidingMappingContext context);
}
public class CycleAvoidingMappingContext {
private Map<Object, Object> knownInstances = new IdentityHashMap<Object, Object>();
public <T> T getMappedInstance(Object source, Class<T> targetType) {
return (T) knownInstances.get( source );
}
public void storeMappedInstance(Object source, Object target) {
knownInstances.put( source, target );
}
}
三、MapToObject互转
public class Source {
private Map<String, Object> map;
}
public class Target {
private String ip;
private String server;
}
( uses = MappingUtil.class )
public interface SourceTargetMapper {
SourceTargetMapper MAPPER = Mappers.getMapper( SourceTargetMapper.class );
(source = "map", target = "ip", qualifiedBy = Ip.class )
(source = "map", target = "server", qualifiedBy = Server.class )
Target toTarget(Source s);
}
public class MappingUtil {
(ElementType.METHOD)
(RetentionPolicy.SOURCE)
public @interface Ip {
}
(ElementType.METHOD)
(RetentionPolicy.SOURCE)
public static @interface Server {
}
public String ip(Map<String, Object> in) {
return (String) in.get("ip");
}
public String server(Map<String, Object> in) {
return (String) in.get("server");
}
}
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;
}
public interface MapToBeanMapper {
MapToBeanMapper INSTANCE = Mappers.getMapper(MapToBeanMapper.class);
(target = "department", ignore = true)
Employee fromMap(Map<String, String> map);
default void finishEmployee( Employee employee, Map<String, String> map) {
employee.setDepartment(fromMapToDepartment(map));
}
(target = "id", source = "did")
(target = "name", source = "dname")
Department fromMapToDepartment(Map<String, String> map);
}
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);
}
四、SPI实现
//主要是用于一些特定的规则处理
step-1:
public class CustomAccessorNamingStrategy extends DefaultAccessorNamingStrategy {
public boolean isGetterMethod(ExecutableElement method) {
String methodName = method.getSimpleName().toString();
return !methodName.startsWith( "with" ) && method.getReturnType().getKind() != TypeKind.VOID;
}
public boolean isSetterMethod(ExecutableElement method) {
String methodName = method.getSimpleName().toString();
return methodName.startsWith( "with" ) && methodName.length() > 4;
}
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
五、lombok配置
这主要是配置,以指定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>