Search code examples
spring-boothibernatespring-rest

Why can not persist data in spring data jpa


While save data in database got exception Cannot handle managed/back reference 'defaultReference': back reference type not compatible with managed type. I got exception while persist data. I think problem is in @JsonManagedReference or @JsonBackReference annotation but can't findout the problem.

Here down is code:

Entity

@Entity
@Table(name = "user_master")
public class Users {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer user_id;

    private String name;

    @JsonManagedReference
    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinTable(name = "users_roles", joinColumns = { @JoinColumn(name = "user_id") }, inverseJoinColumns = {
            @JoinColumn(name = "role_id") })
    private List<Roles> roles;

    // constructor and getter/setter
}

@Entity
@Table(name = "role_master")
public class Roles {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer role_id;

    private String name;

    @JsonBackReference
    @ManyToMany(cascade = CascadeType.ALL, mappedBy = "roles")
    private List<Users> users;

    // constructor and getter/setter
}

Service

@Override
    public List<Users> addUserRole(List<Users> users) {
        for(Users user: users)
        {
            for(Roles role: user.getRoles())
            {
                role.getUsers().add(user);
            }
        }
        return userRepo.saveAll(users);
    }

Controller

@RequestMapping(value = "/adduserrole", method = RequestMethod.POST)
    public ResponseEntity<List<Users>> addUserRole(@RequestBody List<Users> users)
    {
        pojoService.addUserRole(users);
        return ResponseEntity.ok(users);
    }

Postman

[
  {
    "name": "Jack",
    "roles": [
    {
        "name": "Engineer"
    },
    {
        "name": "Doctor"
    },
    {
        "name": "Charter Accountant"
    }
    ]
  }
]

Exception

"message": "Cannot invoke \"java.util.List.add(Object)\" because the return value of \"com.rest.RestApiPojo.Entity.Roles.getUsers()\" is null",

Solution

  • @JsonManagedReference together with @JsonBackReference are supposed to be used in bidirectional relationships of OneToMany in one side and ManyToOne on the other side, or when both sides are of type OneToOne.

    If you inspect closely the JsonBackReference Doc you will understand this

    Value type of the property must be a bean: it can not be a Collection, Map, Array or enumeration. Linkage is handled such that the property annotated with this annotation is not serialized; and during deserialization, its value is set to instance that has the "managed" (forward) link.

    In your case you have bidirectional ManyToMany which means that in both sides there is a reference to a collection. So there is not a single compatible property on the side that you have @JsonBackReference.

    There are 2 solutions in your problem with ManyToMany relationship

    1. Remove both @JsonManagedReference and @JsonBackReference. Pick a side where you want the collection to be serialized and deserialized. Go to the other side where you don't want the other collection to be serialized and deserialized and use the annotation @JsonIgnore.
    2. Use custom Dtos which do not have circular dependencies and let your controller use those Dtos instead of plain entities.

    Also you have another problem as well

    Your controller

    @RequestMapping(value = "/adduserrole", method = RequestMethod.POST)
        public ResponseEntity<List<Users>> addUserRole(@RequestBody List<Users> users)
        {
            pojoService.addUserRole(users);
            return ResponseEntity.ok(users);
        }
    

    expects as input a List of users. Not a single user. So when you want to send a single user your JSON should be

    [
      {
        "name": "Jack",
        "roles": [
        {
            "name": "Engineer"
        },
        {
            "name": "Doctor"
        },
        {
            "name": "Charter Accountant"
        }
        ]
      }
    ]