1

My rest controller returns the same object inifinite times for object USER. Other objects which do not require USER object works fine. What is wrong? If i remove some getters/setters it works ok, but i actually need everything here... Spring throws an exceptions - StackOverFlow exc and Java.lang.IllegalStateException: Cannot call sendError() after the response has been committed

EDIT: I figured out that the problem IS "getRoles()" - unfortunately, it is very important for me and I need to include it in JSON... How to make it work?

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @Column(name = "first_name")
    private String firstName;
    private String surname;
    private String email;
    private String password;

    @ManyToMany
    @JoinTable(
            name = "users_roles",
            joinColumns = @JoinColumn(
                    name = "user_id", referencedColumnName = "id"),
            inverseJoinColumns = @JoinColumn(
                    name = "role_id", referencedColumnName = "id"))
    private List<Role> roles;

    @JsonIgnore
    @ManyToMany
    @JoinTable(
            name="users_documents",
            joinColumns = @JoinColumn(
                    name = "user_id", referencedColumnName = "id"),
            inverseJoinColumns = @JoinColumn(
                    name="document_id", referencedColumnName = "id"))
    private List<Document> usersDocuments;


    @OneToMany(mappedBy="user")
    private List<Document> sharedDocuments;


    public User() {

    }

    public User(String firstName, String surname, String email, String password) {
        this.firstName = firstName;
        this.surname = surname;
        this.email = email;
        this.password = password;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getSurname() {
        return surname;
    }

    public void setSurname(String surname) {
        this.surname = surname;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public List<Role> getRoles() {
        return roles;
    }

    public String getEmail() {
        return email;
    }

    public String getPassword() {
        return password;
    }


    public void setRoles(List<Role> roles) {
        this.roles = roles;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof User)) return false;
        User user = (User) o;
        return getId() == user.getId();
    }

    @Override
    public int hashCode() {
        return Objects.hash(getId());
    }

    @Override
    public String toString() {
        return "User{" +
                "firstName='" + firstName + '\'' +
                ", surname='" + surname + '\'' +
                ", email='" + email + '\'' +
                ", roles=" + roles +
                '}';
    }
}
Arth
  • 331
  • 3
  • 14
  • This is probably related : https://stackoverflow.com/questions/3325387/infinite-recursion-with-jackson-json-and-hibernate-jpa-issue – Arnaud Jul 08 '19 at 14:21
  • 1
    Possible duplicate of [Infinite Recursion with Jackson JSON and Hibernate JPA issue](https://stackoverflow.com/questions/3325387/infinite-recursion-with-jackson-json-and-hibernate-jpa-issue) – Alan Hay Jul 08 '19 at 14:44
  • Do your Roles have users inside of them? If so, make the list of users inside of the role transient or add a jsonignore annotation, including your role class would be helpful here – Zachary Craig Jul 08 '19 at 15:03

1 Answers1

0

Not sure if it is possible for your data specifically, but I was able to solve the issue by using a Set, instead of a list, for just the mapped collections I was having trouble with.

I've noticed a lot of blame going to Jackson for this issue. Although, in my case, I noticed that setting the FetchType to Lazy fixed the issue without a need to modify the Collection type.

I'm guessing this is not going to help your situation, since you need to instantiate all those fields anyway, and lazy loading would just be wasteful in that case.

Nonetheless, you may want to look at all of the places in your code that you are instantiating objects with associations to other entities and check if any extra objects are being eagerly instantiated on accident.

Your equals() method seems to follow best practice perfectly. Though, I'm actually not sure if you are creating a User object there, in which case, as a side-effect, the associated objects of a User are going to be eagerly instantiated.

I could be terrible wrong about that (sorry, unable to check at the moment), but you may want to keep an eye out for similar scenarios if you are stuck and can neither utilize lazy loading nor opt for Sets over Lists in the problematic cases.

Christian Meyer
  • 605
  • 8
  • 15