Abhishek Jaiswal
Abhishek Jaiswal

Reputation: 11

Spring Boot JPA Many to many relationship. Getting unexpected response

I have two entity User and Group and the relationship between both entities are many-to-many. When I call view-group/groupName, I am getting the list of users of group as expected. But when I call view-user/userEmail, I am not getting the list of groups with user details of which user is part of.

Group.java

@Entity
@Table(name = "group_")
public class Group {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @NotBlank
    private String groupName;

    @ManyToMany
    @JoinTable(name = "group_user", 
              joinColumns = { @JoinColumn(name = "group_id") }, 
              inverseJoinColumns = {@JoinColumn(name = "user_id") })
    public Set<User> usersOfgroup = new HashSet<>();

    public Group() {

    } 
}

User.java

@Entity
@Table(name="users")
public class User {
  
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @NotBlank
    @Column(name="name")
    private String name;
    
    @NotBlank
    @Column(name="email")
    private String email;
            
    @JsonIgnore
    @ManyToMany(mappedBy = "usersOfgroup")
    public Set<Group> memberInGroups =new HashSet<>();
    
    public User() {
        
    }

localhost:8080/view-group/groupName

{
    "id": 1,
    "groupName": "Group1",
    "usersOfgroup": [
        {
            "id": 2,
            "name": "Abhishek",
            "email": "[email protected]",
        }
    ]
}

localhost:8080/view-user/[email protected]

{
    "id": 2,
    "name": "Abhishek",
    "email": "[email protected]",
}

Expected response :

{
    "id": 2,
    "name": "Abhishek",
    "email": "[email protected]",
    "memberInGroups":[
          {
            "id": 1,
            "groupName": "Group1",
         }
       ]
}

Upvotes: 1

Views: 1284

Answers (2)

Vedvyas Mohapatra
Vedvyas Mohapatra

Reputation: 146

You can go with below. It will address your immediate need for this specific case. Usually for a many-to-many, bi-directional relationship with lists, usually the solution is to decide which side of your relation is dominant and to have a JsonManagedReference and JsonBackReference combo, or use @JsonIdentityInfo if you have a list. Below is very good read on bidirectional cases to avoid infinite loops..

https://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion

Coming to the solution I am referring to, you will have to override the getter of the list attribute and also use a @JsonInclude

In your Group class - use @JsonIgnore as shown and also put the getter as below to manually kill the loop

@ManyToMany
@JoinTable(name = "group_user", joinColumns = { @JoinColumn(name = "group_id") }, inverseJoinColumns = {
        @JoinColumn(name = "user_id") })
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public Set<User> usersOfgroup = new HashSet<>();

public Set<User> getUsersOfgroup() {
    return this.usersOfgroup.stream().map(user -> {
        user.memberInGroups = new HashSet<>();
        return user;
    }).collect(Collectors.toSet());
}

and in your User class, too do the same.

@ManyToMany(mappedBy = "usersOfgroup")
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public Set<Group> memberInGroups = new HashSet<>();

public Set<Group> getMemberInGroups() {
    return this.memberInGroups.stream().map(group -> {
        group.usersOfgroup = new HashSet<>();
        return group;
    }).collect(Collectors.toSet());
}

Upvotes: 0

Beno
Beno

Reputation: 21

You have added @JsonIgnore on public Set<Group> memberInGroups =new HashSet<>();, thats why the json response doesn't have the data for this. Remove the annotation and you will see the expected response

The @JsonIgnore annotation is used to ignore the logical property used in serialization and deserialization.

Upvotes: 1

Related Questions