我想知道Mapstruct是否以及如何帮助映射具有双向关系的对象(在我的例子中是一对多):
public class A{ private Set<B> listB; public class B{ private A a; }
从实体映射/映射到实体会生成 StackOverflowError 。(我预计这会发生)。另一方面,封闭的Mapstruct问题 469 和 1163 似乎暗示mapstruct不会直接支持它。我试过这个例子:
StackOverflowError
https://github.com/mapstruct/mapstruct-examples/tree/master/mapstruct-mapping-with-cycles
但这是行不通的。无论是否应用"CycleAvoidingMappingContext“,堆栈溢出错误都保持不变。
那么如何使用循环和利用mapstruct来映射对象呢?(我希望避免完全手动映射)
发布于 2019-04-14 14:47:46
为了使映射正常工作,您可以尝试使用以下映射程序:
@Mapper public interface MyMapper { A map(A a, @Context CycleAvoidingMappingContext context); Set<B> map(Set<B> b, @Context CycleAvoidingMappingContext context); B map(B b, @Context CycleAvoidingMappingContext context); }
如果不存在从 Set<B> 映射到 Set<B> 的方法,则不会映射 A 中的集合。
Set<B>
A
发布于 2019-04-16 15:59:20
同时,我找到了一个解决方案:首先忽略有问题的字段,并将其映射到"AfterMapping“中。在我的例子中,我还想独立地映射子对象。在我的例子中, @Context 只包含一个 Boolean ( boolean 不工作),它告诉我进入循环的位置( startedFromPru pru是父进程):
@Context
Boolean
boolean
startedFromPru
父级映射器(包含一组许可证):
@Mapper(componentModel = "spring", uses = {DateTimeMapper.class, LicenseMapper.class, CompanyCodeMapper.class, ProductHierarchyMapper.class}) public abstract class ProductResponsibleUnitMapper { @Autowired private LicenseMapper licenseMapper; @Mappings({@Mapping(target = "licenses", ignore = true)}) public abstract ProductResponsibleUnit fromEntity(ProductResponsibleUnitEntity entity, @Context Boolean startedFromPru); @Mappings({@Mapping(target = "licenses", ignore = true)}) public abstract ProductResponsibleUnitEntity toEntity(ProductResponsibleUnit domain, @Context Boolean startedFromPru); @AfterMapping protected void mapLicenseEntities(ProductResponsibleUnit pru, @MappingTarget ProductResponsibleUnitEntity pruEntity, @Context Boolean startedFromPru){ if(startedFromPru) { pruEntity.getLicenses().clear(); //probably not necessary pru.getLicenses().stream().map(license -> licenseMapper.toEntity(license, startedFromPru)).forEach(pruEntity::addLicense); @AfterMapping protected void mapLicenseEntities(ProductResponsibleUnitEntity pruEntity, @MappingTarget ProductResponsibleUnit pru, @Context Boolean startedFromPru){ if(startedFromPru) { pru.getLicenses().clear(); //probably not necessary pruEntity.getLicenses().stream().map(licenseEntity -> licenseMapper.fromEntity(licenseEntity, startedFromPru)).forEach(pru::addLicense); }
子级映射器:
@Mapper(componentModel = "spring", uses = { DateTimeMapper.class, CompanyCodeMapper.class, ProductHierarchyMapper.class, CountryCodeMapper.class }) public abstract class LicenseMapper { @Autowired private ProductResponsibleUnitMapper pruMapper; @Mappings({ @Mapping(source = "licenseeId", target = "licensee"), @Mapping(target = "licensor", ignore = true) }) public abstract License fromEntity(LicenseEntity entity, @Context Boolean startedFromPru); @Mappings({ @Mapping(source = "licensee", target = "licenseeId"), @Mapping(target = "licensor", ignore = true) }) public abstract LicenseEntity toEntity(License domain, @Context Boolean startedFromPru); @AfterMapping protected void mapPru(LicenseEntity licenseEntity, @MappingTarget License license, @Context Boolean startedFromPru) { //only call ProductResponsibleUnitMapper if mapping did not start from PRU -> startedFromPru is false if (!startedFromPru) { license.setLicensor(pruMapper.fromEntity(licenseEntity.getLicensor(), startedFromPru)); @AfterMapping protected void mapPru(License license, @MappingTarget LicenseEntity licenseEntity,