我在MapStruct中使用spring数据jdbc。 POJO与具有所有“仅限内部”数据(例如代理键,审计信息等)的表结构对齐,而Domain对象是分层的并且仅包含与业务相关的数据。 我必须在特定于表的POJO(平面结构)和带有嵌套对象的Domain对象之间进行映射。如何最好地使用MapStruct 1.2.0做到这一点?
// Pojo for table
public class PersonsRecord {
@Id
private Integer surrogateKey; // should not be mapped
private String loginId;
private String name;
private Timestamp memberSince;
// address columns
private Integer houseNumber;
private String addressStreet;
private String addressCity;
private String country;
// getters and setters
}
// Domain object
public class PersonDto {
private String loginId;
private String name;
private Timestamp memberSince;
private Address address;
}
@Mapper(uses = MapperUtils.class)
public interface PersonMapper {
PersonDto toPersonDto(PersonRecord person);
Address toAddress(PersonRecord person);
}
为toPersonDto
生成的代码将忽略Address
,并且不会调用toAddress
参考提及的MapStruct
方法。可能是因为两种方法都采用相同的输入类型?为toAddress
生成的代码看起来不错。只是MapStruct
世代不会自动将其连接。
反向映射生成类似。没有自动通话。
是否有一种方法可以使此过程自动化(无需自定义方法或装饰器等)?我在很多地方都有类似的模式。
注意:MapperUtils
用于实例化具有不可变字段的DTO。
更新:我使用了Filip的答案,将其从PersonRecord
映射到PersonDto
,包括Person.Address
。对于反向映射,我执行了以下操作:
@Mapper(uses = MapperUtils.class)
public abstract class PersonMapper {
@Mapping(target = "address", source = "person")
public abstract PersonDto toPersonDto(PersonRecord person);
protected abstract Address toAddress(PersonRecord person);
public abstract PersonRecord toRecord(PersonDto dto);
public abstract void updateAddress(PersonDto dto, @MappingTarget PersonRecord person);
@AfterMapping
protected void updateAddress(PersonDto dto, @MappingTarget PersonRecord record) {
updateAddress(dto, record);
}
}
这没有问题。感谢Filip提供的指导。
答案 0 :(得分:1)
未采用toAddress
方法的原因是MapStruct不知道它需要将toPersonDto
参数映射到PersonDto.address
。您还很可能会收到一条警告,指出地址未映射。
为了进行映射,您需要告诉MapStruct如何映射address
。您可以使用@Mapping
来完成。这样,您的映射器就会变成
@Mapper(uses = MapperUtils.class)
public interface PersonMapper {
@Mapper(target = "address", source = "person")
PersonDto toPersonDto(PersonRecord person);
Address toAddress(PersonRecord person);
}
更新,我忘了添加如何执行相反的操作。
执行反向映射的一种方法是使用自定义@Mapping
批注,您将必须对Address
中的每个条目执行此操作。这有点麻烦。有一个开放的MapStruct提取请求,可以更轻松地完成此映射。 PR是mapstruct/mapstruct#1686。
另一种方法是使用多源参数映射。看起来像这样:
@Mapper(uses = MapperUtils.class)
public interface PersonRecordMapper {
default PersonRecord toPersonRecord(PersonDto personDto) {
if (personDto == null) {
return null;
}
return toPersonRecord(personDto, personDto.getAddress());
}
@Mapping(target = "surrogateKey", ignore = true)
PersonRecord toPersonRecord(PersonDto personDto, Address address);
}
当且仅当@Mapping
中的名称属性与Address
中的名称属性匹配时,这才可以在没有手册PersonRecord
的情况下工作。否则,您仍然需要定义@Mapping
。