定义自定义MapStruct映射器,而不必定义所有字段的映射



假设我有两个dto,我希望用MapStruct对它们进行映射,DTO1和DTO2具有基本相同的字段,只是命名不同,我希望将它们从一个映射到另一个。使用MapStruct,我可以这样做:

@Mapping(target = "desiredName", source = "notDesiredName")
// etc
DTO1 toDto1(Dto2 dto2);

但是假设我在Dto2中只有一个属性,我想首先通过一个函数传递。我知道我可以:

default DTO1 toDto1(Dto2 dto2) {
...
dto1.setSomething(myFunction(dto.getSomething)
...
}

如何避免必须重新定义每个其他属性转换?

默认情况下,Mapstruct将自动传输所有具有相同名称/类型的字段。为了干预自动完成的操作,请使用@AfterMapping注释和代码,只使用例外。(或使用@BeforeMapping)

import org.mapstruct.AfterMapping;
import org.mapstruct.Mapper;
import org.mapstruct.MappingTarget;
import com.example.demo.dto.Dto1;
import com.example.demo.dto.Dto2;
@Mapper
public abstract class DtoMapper {
@Mapping(target = "desiredName", source = "notDesiredName")
@AfterMapping
protected void interveneWithSomethingThatChanges (Dto1 dto1, @MappingTarget Dto2 dto2) {
dto2.somethingThatChanges = dto1.somethingThatChanges + ": changed";
}
public abstract Dto2 toDto2(Dto1 dto1);
}

剩余代码如下:

MapperMain.java

import org.mapstruct.factory.Mappers;
import com.example.demo.dto.Dto1;
import com.example.demo.dto.Dto2;
import com.example.demo.mapper.DtoMapper;
public class MapperMain {
public static void main(String[] args) {
final DtoMapper mapper
= Mappers.getMapper(DtoMapper.class);

Dto1 dto1 = new Dto1("somethingThatChanges", "somethingThatStaysTheSame", "somethingElseThatStaysTheSame");
Dto2 dto2 = mapper.toDto2(dto1);

System.out.println(dto2);

}
}

输出:

Dto2 [somethingThatChanges=somethingThatChanges: changed, somethingThatStaysTheSame=somethingThatStaysTheSame, desiredName=somethingElseThatStaysTheSame]

Dto1.java

public class Dto1 {
public String somethingThatChanges;
public String somethingThatStaysTheSame;
public String notDesiredName;
public Dto1(String somethingThatChanges, String somethingThatStaysTheSame, String notDesiredName) {
this.somethingThatChanges = somethingThatChanges;
this.somethingThatStaysTheSame = somethingThatStaysTheSame;
this.notDesiredName = notDesiredName;
}
}

Dto2.java

public class Dto2 {
@Override
public String toString() {
return "Dto2 [somethingThatChanges=" + somethingThatChanges + ", somethingThatStaysTheSame="
+ somethingThatStaysTheSame + ", desiredName=" + desiredName + "]";
}
public String somethingThatChanges;
public String somethingThatStaysTheSame;
public String desiredName;
}

如果你有一个自定义函数来映射一个特定的属性,你可以使用限定符。

@Mapper
public interface MyMapper {

@Mapping(target = "something", qualifiedByName = "customSomething")
DTO1 toDto1(Dto2 dto2);
@Named("customSomething")
default String mapSomething(String value) {
// perform mapping
}
}

让我们来消化一下这个例子。在本例中,DTO1DTO2都有一个名为something的字段。因此,我们只需要定义Mapping#target(当目标和源匹配时,Mapping#source就过时了)。

下一个事实是,我们想执行一些特殊的方式来映射这个字段。我们用Mapping#qualifiedByName来定义它。这告诉MapStruct查找带有@Named("customSomething")注释的自定义映射方法。

mapSomething方法是一个带有@Named("customSomething")注释的自定义方法,这告诉MapStruct这是一个特殊的映射方法,它应该只在用户特别请求(使用Mapping#qualifiedBy)时使用