问题
We are mapping a object that have a list of object that all implement a parent interface but may have a different implementation. But it seem when we are mapping the list only the value from ParentClass was mapped not the value from the child. But mapping directly the child workfine.
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;
}
The mappers
@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);
}
When with this if we map a object ChildClass1 containing ChildClass2 and ChildClass1 in a list we get.
object to map: the object ChildClass1 would look like this in json format:
{
"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"
}
]
}
But when we use the mapper above to map to dto we get:
{
"name":"myName",
"anotherParentField":"10",
"customCLass1Field":"custom name",
"relation":[
{
"name":"firstRelationName",
"anotherParentField":"110",
},
{
"name":"secondRelationName",
"anotherParentField":"110",
}
]
}
None of the field from the child class are mapped. What's missing ?
回答1:
I don't see another way than have a custom mapper.
Here is my solution with what they call 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
}
}
And in ParentClassMapper add the @DecoratedWith annotation:
@Mapper
@DecoratedWith(ParentClassMapperDecorator.class)
public interface ParentClassMapper {
ParentClassDto convertToDto(ParentClass p);
ParentClass convertDTOToModel(ParentClassDto dto);
}
For the 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);
}
If you want to test:
@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);
}
来源:https://stackoverflow.com/questions/55444711/mapping-element-of-a-list-of-different-type-with-mapstruct