java mapstruct 1.3.1 忽略双向 DTO 映射列表中的属性

标签 java mapping mapstruct bidirectional

我正在努力解决 MapStruct 的循环依赖问题。 由于循环依赖,我一直遇到 StackOverFlow 错误。 为了避免这种情况,我只需要排除列表的一个属性。 我发现了这个:https://github.com/mapstruct/mapstruct/issues/933 我深入浏览了互联网,令我惊讶的是我找不到任何完整的示例来显示与 MapStruct 的双向 DTO 映射(除了使用 @Context CycleAvoidingMappingContext ,对我不起作用)。

[编辑]:通过 MapStruct 聊天,我找到了解决方法,我将其添加到 EditorMapper

这是我的情况,我猜很常见: 我有 2 个相互引用的 DTO:

public class BookDTO {

    private Long id;

    private String title;

        //... other properties

    //@JsonManagedReference --> not necessary anymore
    private EditorDTO editor;
}
public class EditorDTO {

    private Long id;
    private String name;

        //...other properties

    //@JsonBackReference --> not necessary anymore
    private List< BookDTO > bookList;
}

而且我需要 MapStruct 能够从编辑器中的 BookList 中排除属性 Editor,然后避免无限循环。 以下是我目前作为映射器所拥有的:

@Mapper
public interface BookMapper {

    BookMapper INSTANCE = Mappers.getMapper( BookMapper.class );

    @Mapping( target = "editor.bookList", ignore = true)
    BookDTO toDTO( BookEntity bookEntity );

    @Named( "NoEditor" )
    @Mapping(target = "editor", ignore = true)
    BookDTO toDTONoEditor( BookEntity bookEntity );

    List<BookDTO> toDTOList( List<BookEntity> bookEntityList );

    @Named( "NoEditor" )
    @IterableMapping(qualifiedByName="NoEditor")
    List<BookDTO> toDTOListNoEditor( List<BookEntity> bookEntityList );

    @Mapping( target = "editor.bookList", ignore = true)
    BookEntity toEntity( BookDTO bookDTO );

    List<BookEntity> toEntityList( List<BookDTO> bookDTOList );
}
@Mapper(uses = BookMapper.class)
public interface EditorMapper {

    EditorMapper INSTANCE = Mappers.getMapper( EditorMapper.class );

    @Named( "NoEditor" )
    @Mapping(target = "bookList", qualifiedByName = "NoEditor")
    EditorDTO toDTO( EditorEntity editorEntity );

    @Named( "NoEditor" )
    @IterableMapping(qualifiedByName="NoEditor")
    List<EditorDTO> toDTOList( List< EditorEntity > editorEntityList );

    EditorEntity toEntity( EditorDTO editorDTO );

    List<EditorEntity> toEntityList( List< EditorDTO > editorDTOList );
}

[编辑]:它现在可以工作,但不是 100% 干净(请参阅我发布的答案以了解更多详细信息)

我也在mappers中尝试过这种方法,但对我的pb没有任何影响。

BookDTO toDTO( BookEntity bookEntity, @Context CycleAvoidingMappingContext context );

有人知道我做错了什么吗?多谢! :)

最佳答案

[编辑]:我也添加了双向 ManyToMany 映射的解决方案 感谢https://gitter.im/mapstruct/mapstruct-users# ,我已经能够得到解决方案。 [编辑]:我仍然有一些我没有意识到的错误。此更新现已更正。 我不得不 : - 将 uses 属性添加到 EditorMapper:@Mapper(componentModel = "spring", uses = BookMapper.class) - 在 BookMapper 中添加替代方法,例如 toDTONoEditortoDTOListNoEditor,其中我忽略 editor 属性。 - 在 EditorMapper 中映射这些替代方法 - 每个循环依赖都相同

解决方案如下:

BookDTO

public class BookDTO {

    private Long id;

    private String title;

        //... other properties

    private EditorDTO editor;
    private List< CategoryDTO > categoryList;
}

EditorDTO

public class EditorDTO {

    private Long id;
    private String name;

        //...other properties

    private List< BookDTO > bookList;
}

类别DTO

public class CategoryDTO {

    private Long id;

    private String category;

    private List< BookDTO > bookList;
}

BookMapper

@Mapper(componentModel = "spring", uses = {CategoryMapper.class, EditorMapper.class})
public interface BookMapper {


    @Named( "NoBook" )
    @Mappings( {
            @Mapping(target = "categoryList", qualifiedByName = "NoBook"),
            @Mapping( target = "editor.bookList", ignore = true)
    } )
    BookDTO toDTO( BookEntity bookEntity );

    @Named( "NoEditor" )
    @Mappings( {
            @Mapping(target = "editor", ignore = true),
            @Mapping(target = "categoryList", qualifiedByName = "NoBook")
    } )
    BookDTO toDTONoEditor( BookEntity bookEntity );

    @Named( "NoCategory" )
    @Mappings( {
            @Mapping(target = "categoryList", ignore = true),
            @Mapping(target = "editor", qualifiedByName = "NoBook")
    } )
    BookDTO toDTONoCategory( BookEntity bookEntity );


    @Named( "NoBook" )
    @IterableMapping(qualifiedByName="NoBook")
    List<BookDTO> toDTOList( List<BookEntity> bookEntityList );

    @Named( "NoEditor" )
    @IterableMapping(qualifiedByName="NoEditor")
    List<BookDTO> toDTOListNoEditor( List<BookEntity> bookEntityList );

    @Named( "NoCategory" )
    @IterableMapping(qualifiedByName="NoCategory")
    List<BookDTO> toDTOListNoCategory( List<BookEntity> bookEntityList );


    @Named( "NoBook" )
    @Mappings( {
            @Mapping(target = "categoryList", qualifiedByName = "NoBook"),
            @Mapping( target = "editor.bookList", ignore = true)
    } )
    BookEntity toEntity( BookDTO bookDTO );

    @Named( "NoCategory" )
    @Mapping(target = "categoryList", ignore = true)
    BookEntity toEntityNoCategory( BookDTO bookDTO );


    @Named( "NoBook" )
    @IterableMapping(qualifiedByName="NoBook")
    List<BookEntity> toEntityList( List<BookDTO> bookDTOList );

    @Named( "NoCategory" )
    @IterableMapping(qualifiedByName="NoCategory")
    List<BookEntity> toEntityListNoCategory( List<BookDTO> bookDTOList );
}

EditorMapper

@Mapper(componentModel = "spring", uses = BookMapper.class)
public interface EditorMapper {

    @Named( "NoEditor" )
    @Mapping(target = "bookList", qualifiedByName = "NoEditor")
    EditorDTO toDTO( EditorEntity editorEntity );

    @Named( "NoBook" )
    @Mapping(target = "bookList", ignore = true)
    EditorDTO toDTONoBook( EditorEntity editorEntity );


    @Named( "NoEditor" )
    @IterableMapping(qualifiedByName="NoEditor")
    List< EditorDTO > toDTOList( List< EditorEntity > editorEntityList );

    @Named( "NoBook" )
    @IterableMapping(qualifiedByName="NoBook")
    List< EditorDTO > toDTOListNoBook( List< EditorEntity > editorEntityList );

    @Named( "NoBook" )
    @Mapping(target = "bookList", qualifiedByName = "NoBook")
    EditorEntity toEntity( EditorDTO editorDTO );

    @Named( "NoBook" )
    @IterableMapping(qualifiedByName="NoBook")
    List< EditorEntity > toEntityList( List< EditorDTO > editorDTOList );
}

类别映射器

@Mapper(componentModel = "spring",uses = BookMapper.class)
public interface CategoryMapper {


    @Named( "NoCategory" )
    @Mapping(target = "bookList", qualifiedByName = "NoCategory")
    CategoryDTO toDTO( CategoryEntity categoryEntity );

    @Named( "NoBook" )
    @Mapping(target = "bookList", ignore = true)
    CategoryDTO toDTONoBook( CategoryEntity categoryEntity );


    @Named( "NoCategory" )
    @IterableMapping(qualifiedByName="NoCategory")
    List<CategoryDTO> toDTOList( List< CategoryEntity > categoryEntityList );

    @Named( "NoBook" )
    @IterableMapping(qualifiedByName="NoBook")
    List<CategoryDTO> toDTOListNoBook( List< CategoryEntity > categoryEntityList );


    @Named( "NoCategory" )
    @Mapping(target = "bookList", qualifiedByName = "NoCategory")
    CategoryEntity toEntity( CategoryDTO categoryDTO );

    @Named( "NoBook" )
    @Mapping(target = "bookList", ignore = true)
    CategoryEntity toEntityNoBook( CategoryDTO categoryDTO );


    @Named( "NoCategory" )
    @IterableMapping(qualifiedByName="NoCategory")
    List<CategoryEntity> toEntityList( List< CategoryDTO > categoryDTOList );

    @Named( "NoBook" )
    @IterableMapping(qualifiedByName="NoBook")
    List<CategoryEntity> toEntityListNoBook( List< CategoryDTO > categoryDTOList );

}

这样,循环依赖在进入无限循环之前就被打破了。 然而,它的满意度达到 99%,因为 EditorBook 对象并不完全干净。 Editor 包含 bookList。但 bookList 中的每本书仍然包含一个空的 editor 字段。对于 Book 对象反之亦然。 但这似乎是一个反/序列化问题,而不是 MapStruct 问题。 这是 Json 结果

编辑

{
  "id": 1,
  "name": "Folio",
  "coordinates": null,
  "bookList": [
    {
      "id": 1,
      "title": "Le cycle de Fondation, I : Fondation",
      "categoryList": [
        {
          "id": 5,
          "category": "LITERATURE&FICTION"
        }
      ],
      "language": "French",
      "isbn": 2070360539,
      "publicationDate": null,
      "numberOfPages": 416,
      "authorList": [],
      "libraryList": [
        {
          "id": 2,
          "name": "Library2",
          "coordinates": null
        },
        {
          "id": 1,
          "name": "Library1",
          "coordinates": null
        }
      ],
      "editor": null
    }
  ]
}

预订

{
  "id": 1,
  "title": "Le cycle de Fondation, I : Fondation",
  "categoryList": [
    {
      "id": 5,
      "category": "LITERATURE&FICTION",
      "bookList": null
    }
  ],
  "language": "French",
  "isbn": 2070360539,
  "publicationDate": null,
  "numberOfPages": 416,
  "authorList": [],
  "libraryList": [
    {
      "id": 2,
      "name": "Library2",
      "coordinates": null
    },
    {
      "id": 1,
      "name": "Library1",
      "coordinates": null
    }
  ],
  "editor": {
    "id": 1,
    "name": "Folio",
    "coordinates": null,
    "bookList": null
  }
}

类别

{
  "id": 1,
  "category": "CHILDREN",
  "bookList": [
    {
      "id": 5,
      "title": "Le petit prince",
      "categoryList": null,
      "language": "French",
      "isbn": 9782070612758,
      "publicationDate": null,
      "numberOfPages": 120,
      "authorList": [],
      "libraryList": [
        {
          "id": 2,
          "name": "Library2",
          "coordinates": null
        },
        {
          "id": 1,
          "name": "Library1",
          "coordinates": null
        }
      ],
      "editor": null
    }
  ]
}

希望这有帮助:)

关于java mapstruct 1.3.1 忽略双向 DTO 映射列表中的属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60615525/

相关文章:

.net - NHibernate 通过 where 选择将一张表映射到两个类

java - 带有抽象和通配符的 Mapstruct

java - 遍历/更新 HashMap

java - 如何通过 SDK Java 在 AWS API Gateway 中启用 CORS

math - 在 Direct3D 中使用像素着色器绘制旋转球体

java - Map List<String> with Mapstruct 从 Java POJO 到 Protobuf (proto3)

spring - Mapstruct 中的嵌套映射

java - IOException 无法解析为类型错误

java - 如何导出 jar 中项目的库?

c++ - 当运行时属性名称未知时,按属性对 C++ 对象进行通用聚合