【问题标题】:Infinite recursion with @JsonManagedReference and @JsonBackReference使用@JsonManagedReference 和@JsonBackReference 进行无限递归
【发布时间】:2021-11-15 17:59:10
【问题描述】:

我有一个自引用的实体类。例如,可以将文档链接到父文档。

@Entity
@Table(name = "documents")
public class DocumentEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @JsonIgnore
    @JsonManagedReference
    @ManyToOne(fetch = FetchType.LAZY)
    private DocumentEntity parentDocument;

    @JsonBackReference
    @OneToMany(mappedBy = "parentDocument", fetch = FetchType.LAZY)
    private Set<DocumentEntity> documents;

    @Column(nullable = false, unique = true)
    private String documentId;

    @Column(nullable = false)
    private String fileName;
}

在我的入口点/控制器层:

@GetMapping(
        path = "/{fileId}",
        produces = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE }
)
public DocumentResponse getParentDocument(@PathVariable("fileId") String fileId) {
    modelMapper = createModelMapper();
    DocumentDto documentDto = documentService.getParentDocument(fileId);
    DocumentResponse documentResponse = modelMapper.map(documentDto, DocumentResponse.class);
    documentResponse.getDocuments().forEach(document -> System.out.println(document.getDocumentId()));
    return documentResponse;
}

在我的服务层:

@Override
public DocumentDto getParentDocument(String documentId) {
    DocumentDto documentDtoResponse = new DocumentDto();

    ModelMapper modelMapper = new ModelMapper();
    modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);

    DocumentEntity storedDocumentEntity =
            documentRepository.findByDocumentIdAndParentDocumentNull(documentId);
    if(storedDocumentEntity.getDocumentId().isEmpty() || storedDocumentEntity.getDocumentId().isBlank()) {
        throw new AppFileNotFoundException("Oops file not found");
    }
    documentDtoResponse = modelMapper.map(storedDocumentEntity, DocumentDto.class);

    return documentDtoResponse;
}

在存储库中:

现在我在扩展 JpaRepository 的存储库接口中发出 sql 请求。 应用程序允许父文档有子文档,子文档不能有子文档。

@Repository
public interface DocumentRepository extends JpaRepository<DocumentEntity, Long> {
    DocumentEntity findByDocumentIdAndParentDocumentNull(String documentId);
}

我也尝试使用 JPQL 实现该方法:

@Query("SELECT d FROM DocumentEntity d WHERE d.documentId = :documentId AND d.parentDocument IS NULL")
DocumentEntity findByDocumentIdAndParentDocumentNull(String documentId);

此查询允许获取父文档和子文档。 我的代码实现使用 DTO 层将响应和数据库分开。

问题:

我的问题是我获得了无限递归。我想我正确地使用了@JsonManagedReference 和@JsonBackReference。即使向 DTO pojo 添加相同的注释也不能解决问题。如果我将这些注释添加到响应 POJO,那么我不会获得子文档。

无法编写 JSON:无限递归 (StackOverflowError);嵌套异常是 com.fasterxml.jackson.databind.JsonMappingException

【问题讨论】:

标签: spring-boot hibernate jpa modelmapper


【解决方案1】:

最初我有一个 DTO 类,它也自我引用自己。

public class DocumentDto implements Serializable {
    private String filePath;
    private String mimeType;
    private String documentType;
    private DocumentDto parentDocument;
    Set<DocumentDto> documents;
}

我创建了第二个类,但没有导致问题的属性;

public class DocumentChildDto implements Serializable {
    private String filePath;
    private String mimeType;
    private String documentType;
}

在 DocumentDto 中,我只是将 DocumentDto 替换为 DocumentChildDto。

public class DocumentDto implements Serializable {
    private String filePath;
    private String mimeType;
    private String documentType;
    private DocumentChildDto parentDocument;
    Set<DocumentChildDto> documents;
}

与其说是技术解决方案,不如说是一种 hack,但它运行良好。这里 childDocumentDto 对象不会加载 parentDocument。

【讨论】:

    猜你喜欢
    • 2015-09-27
    • 2020-04-23
    • 2016-09-20
    • 1970-01-01
    • 2017-07-30
    • 2016-11-07
    • 1970-01-01
    • 2018-04-15
    • 2021-03-05
    相关资源
    最近更新 更多