1

I have a many to many relationship in my project between User and a Product. A User can have many products and a Product can be owned by many Users.

User.java

    @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinTable( name = "user_product",
                joinColumns = @JoinColumn(name = "user_id"),
                inverseJoinColumns = @JoinColumn(name = "product_id"))
    private List<Product> listOfProductsForUser;

Product.java

    @JsonIgnore
    @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "listOfProductsForUser")
    private List<User> listOfUsersForProduct;

In my controller, I have a path that gets me all the users and the nested products associated with the user like this.

[
    {
        "userId": 1,
        "userName": "Fido",
        "age": 3,
        "listOfProductsForUser": [
            {
                "productId": 1,
                "productName": "tooth brush",
            },
            {
                "productId": 2,
                "productName": "potatoes",
            },
            {
                "productId": 3,
                "productName": "carrot",
            }
        ]
    },
    {
        "userId": 2,
        "userName": "David",
        "age": 12,
        "listOfProductsForUser": [
            {
                "productId": 6,
                "productName": "oranges",
            },
            {
                "productId": 7,
                "productName": "tomatoes",
            },
            {
                "productId": 6,
                "productName": "buns",
            }
        ]
    }
]

This is fine but I now want to get all products which should have nested users (to get all products and see which users are using them). While attempting to do this I run into a recursive problem and I have used JsonIgnore on the product.java's listOfProductsForUser variable as shown above to stop the recursion. How can I accomplish this?

1
  • If @JsonIgnore doesn't meet your needs, you may want to look at @JsonManagedReference and @JsonBackReference. Commented Sep 30, 2021 at 18:24

2 Answers 2

3

There are couple of ways to deal with this bi-directional relationship issue. I think @JsonIdentityInfo is the best way in your case.

What you need to do is change your User and Product class as follows.

//other annotations
@JsonIdentityInfo(
  generator = ObjectIdGenerators.PropertyGenerator.class, 
  property = "userId")
public class User {
    // your code
}
//other annotations
@JsonIdentityInfo(
  generator = ObjectIdGenerators.PropertyGenerator.class, 
  property = "productId")
public class Product {
    // your code
}

Note: For more info here

Sign up to request clarification or add additional context in comments.

Comments

1

Try the following:

@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinTable( name = "user_product",
            joinColumns = @JoinColumn(name = "user_id"),
            inverseJoinColumns = @JoinColumn(name = "product_id"))
@JsonManagedReference
private List<Product> listOfProductsForUser;
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "listOfProductsForUser")

@JsonBackReference
private List<User> listOfUsersForProduct;

These two annotations (@JsonManagedReference and @JsonBackReference) avoid infinite recursion.


I misunderstood the question. Both listOfUsersForProduct and listOfProductsForUsershould be present in the JSON. The previous solution omits listOfUsersForProduct. To have both you need to use @JsonIdentityInfo as @ray already suggested:

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "userId")
public class User { }
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "productId")
public class Product { }

8 Comments

It stops the recursion but I still can not get the array of User listOfUsersForProduct when I get all the products.
That is in fact weird. Try swapping the annotations. I've edited my answer.
I swapped it. Now it flipped. I can now access the list of Users through listOfUsersForProduct array but I cannot get the list of Products through listOfProductsForUser when I getAll from the UserRepository.
Wait, do you want to have both listOfUsersForProduct and listOfProductsForUser? In that case, I misunderstood your question.
I've updated my answer. It is basically what @ray already suggested, so kudos to him. If it actually works accept and upvote his answer and upvote mine ;)
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.