JPA/Hibernate bidirectional many-to-one results in StackOverflowException
Asked Answered
S

1

9

I have entities User and GrantedRole that have a bidirectional one-to-many relation.

When I try to add a GrantedRole to the Set in User, there is no exception thrown, but when I debug the variables for the User and GrantedRole object have a description that reads

com.sun.jdi.InvocationException occurred invoking method.

The different fields for the variables can be read while debugging, but when I select the roles field in User or the user field in GrantedRole I get the same description as above. When I go into the Set of GrantedRole in user, I eventually find the following description:

Detail formatter error: An exception occurred: java.lang.StackOverflowError

My code:

public class User {
    private Set<GrantedRole> roles = new HashSet<GrantedRole>();

    public User() {
        super();
    }
    public User(String name, String password) {
        this.name = name;
        this.password = password;
    }

    @OneToMany(fetch = FetchType.EAGER, mappedBy = "user")
    public Set<GrantedRole> getRoles() {
        return roles;
    }

    public void setRoles(Set<GrantedRole> roles) {
        this.roles = roles;
    }

    // equals and hashCode are based on username
    // toString is based on all fields
}

public class GrantedRole {
    private user user;

    public GrantedRole() {
        super();
    }
    public GrantedRole(User user, Role role, Organization organization) {
        this.user = user;
        this.role = role;
        this.organization = organization;
    }

    @ManyToOne
    @NotNull
    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    // equals and hashCode are based on all fields
    // toString was based on all fields, I've changed it to not include User.
}

public class Test {
    public void testStuff() {
        User user = new User("name");
        GrantedRole role = new GrantedRole(user, "role"); //this sets the user field
        user.getRoles().add(role); //doesn't throw Exception, but debugging shows InvocationTargetException and StackOverflowException
        System.out.println(user.getRoles()); //throws StackOverflowException, as I would expect
    }
}

It was my understanding that I should be able to set up a bidirectional relation in this way. I read multiple tutorials, like this one, and I don´t see what I am doing differently to cause the .add(role) to go wrong.

I left out some trivial code, if it is needed I will gladly provide it. I haven't made code to ensure that a GrantedRole with a reference to a User is referenced by that user in return, but I think that is not relevant for the problem I'm having.

Superscribe answered 19/6, 2013 at 15:21 Comment(5)
1. Are the getters/setters really trivial? 2. The full stack of the StackOverflowError would help a lot to understand what is happening.Wileywilfong
And you can add the code of both constructors, User(String) and GrantedRole(User, String), so that we can understand what you're doing exactly.Apeak
It might the toString() method recursive call. You should make sure that you don't call the methods like equals, hashCode, ... from child in parent, only child should be interested in calling from parent.Amylopectin
I just realized that the reason the description when debugging shows the exceptions, is because it is trying to print the variables, which causes the exception.Superscribe
I've updated my question to include the information requested, apart from the Exception. I was just being stupid and have solved the problem. I will post it as an answer.Superscribe
S
19

So, I was just being stupid and had a recursive call in the toString() methods. User.toString() tried to print the roles, and GrantedRole.toString() tried to print the user.

I fixed it by altering the GrantedRole.toString() to print user.getUsername(), thus breaking the cycle.

Superscribe answered 20/6, 2013 at 8:29 Comment(3)
the same can happen with your .hashCode() method :)Gustavogustavus
Thanks, stuck with this stackoverflow issue for more than a day for one to one bidirectional.Resolved the issue by modifing the tostring()Boss
I can confirm this. We also had a Stackoverflow and thought we need to specify all ManyToOne combinations with @JsonManagedReference/@JsonBackReference. But in the end I just commented all toString() methods of the entities out and then one by one back in and realized two entities created an infinite loop in their toString Methods.Jankell

© 2022 - 2024 — McMap. All rights reserved.