我想知道Mapstruct是否以及如何帮助具有双向关系(在我的情况下是一对多)的映射对象:
public class A{
private Set<B> listB;
}
public class B{
private A a;
}
从/到实体的映射产生StackOverflowError
。 (我希望这会发生)。
另一方面,封闭的Mapstruct问题469和1163似乎暗示mapstruct将不会直接支持它。
我尝试了以下示例:
https://github.com/mapstruct/mapstruct-examples/tree/master/mapstruct-mapping-with-cycles
但这是行不通的。无论是否应用“ CycleAvoidingMappingContext”,stackoverflowerror都保持不变。
那么如何使用循环映射对象并利用mapstruct? (我想避免完整的手动映射)
答案 0 :(得分:0)
为了使映射起作用,您可以尝试使用以下映射器:
@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
中的集合将不会被映射。
答案 1 :(得分:0)
在此期间,我找到了一个解决方案:首先,我忽略了所讨论的字段,并将其映射到“ AfterMapping”中。就我而言,我也想独立映射孩子。在我的情况下,@Context
仅包含一个Boolean
(boolean
不起作用),它告诉我进入周期的位置(startedFromPru
pru是父级):
父级映射程序(包含一组许可证):
@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,
@Context Boolean startedFromPru) {
//only call ProductResponsibleUnitMapper if mapping did not start from PRU -> startedFromPru is false
if (!startedFromPru) {
licenseEntity.setLicensor(pruMapper.toEntity(license.getLicensor(), startedFromPru));
}
}