0
votes

I have an entity class that is self referencing itself. For example, a document can be linked to a parent document.

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

In my entry point / controller layer :

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

In my Service layer :

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

In the repository:

Now I'm making a sql request in a repository interface that extends JpaRepository. The application allow to have a parent document with child documents and child documents cannot have child documents.

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

I also tried to implement the method using JPQL :

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

This query allow to get parent documents and child documents. My code implementation separates response and database by using a DTO layer.

Issue:

My issue is that I obtain an infinite recursion. I think i'm using @JsonManagedReference and @JsonBackReference correctly. Even adding the same annotations to DTO pojo do not solve issue. If i add those annotation to response POJO, then I do not obtain child documents.

Could not write JSON: Infinite recursion (StackOverflowError); nested exception is com.fasterxml.jackson.databind.JsonMappingException

1
Helpful but it didn't helped me really. I solved my issue with a simple trick. - davidvera

1 Answers

0
votes

Inially I have a DTO class that also self refers to itself.

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

I created a second class without properties that are causing problems;

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

In the DocumentDto I simply replaced the DocumentDto with DocumentChildDto.

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

It's more a hack than a technical solution but it works fine. Here childDocumentDto object won't load the parentDocument.