java - 使用mapstruct映射不同类型列表的元素

标签 java mapstruct

我们正在映射一个对象,该对象具有一个对象列表,这些对象都实现了父接口(interface),但可能具有不同的实现。 但当我们映射列表时,似乎只有来自 ParentClass 的值被映射,而不是来自子类的值。 但直接映射子进程就可以了。

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);
}

使用此方法时,如果我们将包含 ChildClass2 和 ChildClass1 的对象 ChildClass1 映射到我们得到的列表中。

要映射的对象: 对象 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",
      }
   ]
}

子类中的任何字段都没有被映射。 缺少什么?

最佳答案

除了自定义映射器之外,我没有看到其他方法。

这是我的解决方案,他们称之为 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中添加@DecolatedWith注释:

@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);
  }

关于java - 使用mapstruct映射不同类型列表的元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55444711/

相关文章:

在 Weblogic 12c 中运行 Fabric-sdk-java 时出现 java.lang.NoSuchMethodError : com. google.common.util.concurrent.MoreExecutors.platformThreadFactory()

java - EMR - Hive 和 Java 结合在一起

java - 如何向所有登录用户发送通知

java - Mapstruct映射: Return null object if all source parameters properties are null

java - 使用相同输入类型的多个子映射器

java - 花语 POS : error in building jar file using maven

java - 为什么SpringApplication通过配置加载ApplicationContextInitializer?

java - 如何针对不同的数据类型使用MapStruct?

gradle - MapStruct和不可变

java - 无法使用 MapStruct 映射 Integer 中的枚举