2
votes

I am having trouble saving my entities via REST with Spring Data Rest. As you can see below I have a circular dependency which I try to solve with Jackson. This is a small example explaining the problem.

Account

@Entity
@JsonIdentityInfo(property = "id", generator = ObjectIdGenerators.PropertyGenerator.class)
public class Account implements Serializable
{
    @Id <...>
    private Long id;

    private String uid;

    @OneToMany <...>
    //@JsonIdentityReference
    private List<AccountIdentifier> identifiers;

    // Getters, Setters ...
}

AccountIdentifier

@Entity
@JsonIdentityInfo(property = "id", generator = ObjectIdGenerators.PropertyGenerator.class)
public class AccountIdentifier implements Serializable
{
    @Id <...>
    private Long id;

    private String value;

    @ManyToOne <...>
    //@JsonIdentityReference(alwaysAsId = true)
    private Account account;

    // Getters, Setters ...
}

AccountRepository

@RepositoryRestResource(collectionResourceRel = "accounts", path = "accounts")
public interface AccountRepository extends PagingAndSortingRepository<Account, Long>

AccountIdentifierRepository

@RepositoryRestResource(collectionResourceRel = "accountidentifiers", path = "accountidentifiers")
public interface AccountRepository extends PagingAndSortingRepository<AccountIdentifier, Long>

With this setup I can perfectly read values stored in my database.

The Problem starts, when I want to save values via POST to my /accounts endpoint. I want to save the following JSON:

 '{"id":null, "uid":"test-uid", "identifiers":[{"id":null,"value":"test-value"}]}'

This raises a JsonMappingException:

com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: demo.domains.AccountIdentifier["account"]->demo.domains.Account["identifiers"]->java.util.ArrayList[0]->demo.domains.AccountIdentifier["account"]-[...]

When I annotate both entities with @JsonIdentityReference I get NullPointerExceptions on the circular reference.

com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: demo.domains.Account["identifiers"]->java.util.ArrayList[0]->demo.domains.AccountIdentifier["account"])

Is there any way to store both the Account and the nested AccountIdentifier with "id":null? I want to avoid to do two POSTs to the different endpoints. Using @JsonManagedReference and @JsonBackReference has other unwanted drawbacks.

It works perfectly when I use the entity objects in Java code.

1

1 Answers

0
votes

I think you have no choice and must do various POST. I've struggled a lot with that, playing with bi- and uni-directional associations, to arrive at this conclusion.

The easiest you can do is to POST on /account with an empty identifiers, then on /accountidentifiers with an account field equals to the location field inside the answer to your first POST, and you won't need to PATCH again your account entity to update the relationship.