Mapping element of a list of different type with mapstruct

梦想与她 提交于 2019-12-11 04:48:39

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!