使用 mapstruct 映射不同类型列表的元素
Mapping element of a list of different type with mapstruct
我们正在映射一个 object,它有一个 object 的列表,它们都实现了一个 parent 接口,但可能有不同的实现。
但是当我们映射列表时,似乎只有来自 ParentClass 的值被映射,而不是来自 child 的值。
但是直接映射 child 工作正常。
public class ParentClass{
String name;
int anotherParentField;
List<ParentClass> relation;
}
public class ChildClass1 extends ParentClass{
String customCLass1Field;
}
public class ChildClass2 extends ParentClass {
int intField;
}
public class ParentClassDto{
String name;
int anotherParentField;
List<ParentClassDto> relation;
}
public class ChildClass1Dto extends ParentClassDto{
String customCLass1Field;
}
public class ChildClass2Dto extends ParentClassDto {
int intField;
}
映射器
@Mapper
public interface ParentClassMapper{
ParentClassDto convertToDto(ParentClass p);
ParentClass convertDTOToModel(ParentClassDto dto);
}
@Mapper
public interface ChildClass1Mapper implements ParentClassMapper
{
ChildClass1Dto convertToDto(ChildClass1 p);
ChildClass1 convertDTOToModel(ChildClass1Dto dto);
}
@Mapper
public interface ChildClass2Mapper implements ParentClassMapper
{
ChildClass2Dto convertToDto(ChildClass2 p);
ChildClass2 convertDTOToModel(ChildClass2Dto dto);
}
使用此方法时,如果我们映射 object ChildClass1,我们将在列表中包含 ChildClass2 和 ChildClass1。
object 映射:
object ChildClass1 在 json 格式中看起来像这样:
{
"name":"myName",
"anotherParentField":"10",
"customCLass1Field":"custom name",
"relation":[
{
(This is of Object Type : ChildClass1)
"name":"firstRelationName",
"anotherParentField":"110",
"customCLass1Field":"relationcustom name"
},
{
(This is of Object Type : ChildClass2)
"name":"secondRelationName",
"anotherParentField":"110",
"intField":"4"
}
]
}
但是当我们使用上面的映射器映射到 dto 时,我们得到:
{
"name":"myName",
"anotherParentField":"10",
"customCLass1Field":"custom name",
"relation":[
{
"name":"firstRelationName",
"anotherParentField":"110",
},
{
"name":"secondRelationName",
"anotherParentField":"110",
}
]
}
来自 childclass 的字段的 None 被映射。
缺少什么?
除了自定义映射器,我看不到其他方法。
这是我的解决方案,他们称之为 decorator:
public abstract class ParentClassMapperDecorator implements ParentClassMapper {
private final ParentClassMapper delegate;
public ParentClassMapperDecorator(ParentClassMapper delegate) {
this.delegate = delegate;
}
@Override
public ParentClass convertDTOToModel(ParentClassDto dto) {
ParentClass parentClass = null;
if (dto instanceof ChildClass1Dto) {
parentClass = Mappers.getMapper(ChildClass1Mapper.class).convertDTOToModel((ChildClass1Dto) dto);
} else if (dto instanceof ChildClass2Dto) {
parentClass = Mappers.getMapper(ChildClass2Mapper.class).convertDTOToModel((ChildClass2Dto) dto);
} else {
parentClass = this.delegate.convertDTOToModel(dto);
}
return parentClass;
}
@Override
public ParentClassDto convertToDto(ParentClass p) {
// Do the job here
}
}
并在 ParentClassMapper 中添加 @DecoratedWith 注解:
@Mapper
@DecoratedWith(ParentClassMapperDecorator.class)
public interface ParentClassMapper {
ParentClassDto convertToDto(ParentClass p);
ParentClass convertDTOToModel(ParentClassDto dto);
}
对于child:
@Mapper(uses = {ParentClassMapper.class})
public interface ChildClass1Mapper{
ChildClass1Dto convertToDto(ChildClass1 p);
ChildClass1 convertDTOToModel(ChildClass1Dto dto);
}
@Mapper(uses = {ParentClassMapper.class})
public interface ChildClass2Mapper {
ChildClass2Dto convertToDto(ChildClass2 p);
ChildClass2 convertDTOToModel(ChildClass2Dto dto);
}
如果你想测试:
@Test
public void mapStruct_Inheritance_Test() throws Exception {
ChildClass1Dto childClass1Dto = new ChildClass1Dto();
childClass1Dto.name = "name1";
childClass1Dto.anotherParentField = 1;
childClass1Dto.customCLass1Field = "customCLass1Field1";
List<ParentClassDto> parentClassDtos = new ArrayList<>();
ChildClass1Dto childClass11Dto = new ChildClass1Dto();
childClass11Dto.name = "name12";
childClass11Dto.anotherParentField = 12;
childClass11Dto.customCLass1Field = "customCLass1Field12";
parentClassDtos.add(childClass11Dto);
ChildClass2Dto childClass21Dto = new ChildClass2Dto();
childClass21Dto.name = "name12";
childClass21Dto.anotherParentField = 21;
childClass21Dto.intField = 210;
parentClassDtos.add(childClass21Dto);
childClass1Dto.relation = parentClassDtos;
ParentClass parentClass = Mappers.getMapper(ParentClassMapper.class).convertDTOToModel(childClass1Dto);
}
我们正在映射一个 object,它有一个 object 的列表,它们都实现了一个 parent 接口,但可能有不同的实现。 但是当我们映射列表时,似乎只有来自 ParentClass 的值被映射,而不是来自 child 的值。 但是直接映射 child 工作正常。
public class ParentClass{
String name;
int anotherParentField;
List<ParentClass> relation;
}
public class ChildClass1 extends ParentClass{
String customCLass1Field;
}
public class ChildClass2 extends ParentClass {
int intField;
}
public class ParentClassDto{
String name;
int anotherParentField;
List<ParentClassDto> relation;
}
public class ChildClass1Dto extends ParentClassDto{
String customCLass1Field;
}
public class ChildClass2Dto extends ParentClassDto {
int intField;
}
映射器
@Mapper
public interface ParentClassMapper{
ParentClassDto convertToDto(ParentClass p);
ParentClass convertDTOToModel(ParentClassDto dto);
}
@Mapper
public interface ChildClass1Mapper implements ParentClassMapper
{
ChildClass1Dto convertToDto(ChildClass1 p);
ChildClass1 convertDTOToModel(ChildClass1Dto dto);
}
@Mapper
public interface ChildClass2Mapper implements ParentClassMapper
{
ChildClass2Dto convertToDto(ChildClass2 p);
ChildClass2 convertDTOToModel(ChildClass2Dto dto);
}
使用此方法时,如果我们映射 object ChildClass1,我们将在列表中包含 ChildClass2 和 ChildClass1。
object 映射: object ChildClass1 在 json 格式中看起来像这样:
{
"name":"myName",
"anotherParentField":"10",
"customCLass1Field":"custom name",
"relation":[
{
(This is of Object Type : ChildClass1)
"name":"firstRelationName",
"anotherParentField":"110",
"customCLass1Field":"relationcustom name"
},
{
(This is of Object Type : ChildClass2)
"name":"secondRelationName",
"anotherParentField":"110",
"intField":"4"
}
]
}
但是当我们使用上面的映射器映射到 dto 时,我们得到:
{
"name":"myName",
"anotherParentField":"10",
"customCLass1Field":"custom name",
"relation":[
{
"name":"firstRelationName",
"anotherParentField":"110",
},
{
"name":"secondRelationName",
"anotherParentField":"110",
}
]
}
来自 childclass 的字段的 None 被映射。 缺少什么?
除了自定义映射器,我看不到其他方法。
这是我的解决方案,他们称之为 decorator:
public abstract class ParentClassMapperDecorator implements ParentClassMapper {
private final ParentClassMapper delegate;
public ParentClassMapperDecorator(ParentClassMapper delegate) {
this.delegate = delegate;
}
@Override
public ParentClass convertDTOToModel(ParentClassDto dto) {
ParentClass parentClass = null;
if (dto instanceof ChildClass1Dto) {
parentClass = Mappers.getMapper(ChildClass1Mapper.class).convertDTOToModel((ChildClass1Dto) dto);
} else if (dto instanceof ChildClass2Dto) {
parentClass = Mappers.getMapper(ChildClass2Mapper.class).convertDTOToModel((ChildClass2Dto) dto);
} else {
parentClass = this.delegate.convertDTOToModel(dto);
}
return parentClass;
}
@Override
public ParentClassDto convertToDto(ParentClass p) {
// Do the job here
}
}
并在 ParentClassMapper 中添加 @DecoratedWith 注解:
@Mapper
@DecoratedWith(ParentClassMapperDecorator.class)
public interface ParentClassMapper {
ParentClassDto convertToDto(ParentClass p);
ParentClass convertDTOToModel(ParentClassDto dto);
}
对于child:
@Mapper(uses = {ParentClassMapper.class})
public interface ChildClass1Mapper{
ChildClass1Dto convertToDto(ChildClass1 p);
ChildClass1 convertDTOToModel(ChildClass1Dto dto);
}
@Mapper(uses = {ParentClassMapper.class})
public interface ChildClass2Mapper {
ChildClass2Dto convertToDto(ChildClass2 p);
ChildClass2 convertDTOToModel(ChildClass2Dto dto);
}
如果你想测试:
@Test
public void mapStruct_Inheritance_Test() throws Exception {
ChildClass1Dto childClass1Dto = new ChildClass1Dto();
childClass1Dto.name = "name1";
childClass1Dto.anotherParentField = 1;
childClass1Dto.customCLass1Field = "customCLass1Field1";
List<ParentClassDto> parentClassDtos = new ArrayList<>();
ChildClass1Dto childClass11Dto = new ChildClass1Dto();
childClass11Dto.name = "name12";
childClass11Dto.anotherParentField = 12;
childClass11Dto.customCLass1Field = "customCLass1Field12";
parentClassDtos.add(childClass11Dto);
ChildClass2Dto childClass21Dto = new ChildClass2Dto();
childClass21Dto.name = "name12";
childClass21Dto.anotherParentField = 21;
childClass21Dto.intField = 210;
parentClassDtos.add(childClass21Dto);
childClass1Dto.relation = parentClassDtos;
ParentClass parentClass = Mappers.getMapper(ParentClassMapper.class).convertDTOToModel(childClass1Dto);
}