0

Here is my Entity Code,

package com.javaimplant.socialnetwork.model;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

import org.hibernate.annotations.GenericGenerator;

@Entity
@Table(name="users")
public class User {

    @Id
    @Column(name="Id")
    @GenericGenerator(name="inc",strategy = "increment")
    @GeneratedValue(generator = "inc")
    private Integer id;

    @Column(name="name")
    private String userName;

    @Column(name="password")
    private String password;

    @OneToMany(fetch=FetchType.EAGER)
    private List<User> friends= new ArrayList<>();

    public List<User> getFriends() {
        return friends;
    }

    public void setFriends(List<User> friends) {
        this.friends = friends;
    }

    public Integer getId() {
        return id;
    }

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

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

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

I want to make a @OneToMany relation so that user can choose as his friends in a Social Networking App. When I comment the friends attribute and its getters and setters everything works fine. Now when I am adding this attribute I get this below exception.

Here is the stack trace,

java.lang.StackOverflowError
org.hibernate.metamodel.mapping.internal.PluralAttributeMappingImpl$$Lambda$228/666804214.<init>(Unknown Source)
org.hibernate.metamodel.mapping.internal.PluralAttributeMappingImpl$$Lambda$228/666804214.get$Lambda(Unknown Source)
org.hibernate.metamodel.mapping.internal.PluralAttributeMappingImpl.generateFetch(PluralAttributeMappingImpl.java:363)
org.hibernate.loader.ast.internal.LoaderSelectBuilder.lambda$visitFetches$5(LoaderSelectBuilder.java:431)
java.util.ArrayList.forEach(Unknown Source)
org.hibernate.persister.entity.AbstractEntityPersister.visitFetchables(AbstractEntityPersister.java:6174)
org.hibernate.loader.ast.internal.LoaderSelectBuilder.visitFetches(LoaderSelectBuilder.java:460)
org.hibernate.loader.ast.internal.LoaderSqlAstCreationState.visitFetches(LoaderSqlAstCreationState.java:131)
org.hibernate.sql.results.graph.AbstractFetchParent.afterInitialize(AbstractFetchParent.java:31)
org.hibernate.sql.results.graph.entity.internal.EntityResultImpl.<init>(EntityResultImpl.java:52)
org.hibernate.sql.results.graph.entity.internal.EntityResultImpl.<init>(EntityResultImpl.java:34)
org.hibernate.sql.results.graph.entity.internal.EntityFetchJoinedImpl.<init>(EntityFetchJoinedImpl.java:40)
org.hibernate.metamodel.mapping.internal.EntityCollectionPart.generateFetch(EntityCollectionPart.java:130)
org.hibernate.metamodel.mapping.internal.EntityCollectionPart.generateFetch(EntityCollectionPart.java:36)
org.hibernate.loader.ast.internal.LoaderSelectBuilder.lambda$visitFetches$5(LoaderSelectBuilder.java:431)
org.hibernate.metamodel.mapping.PluralAttributeMapping.visitFetchables(PluralAttributeMapping.java:54)
org.hibernate.loader.ast.internal.LoaderSelectBuilder.visitFetches(LoaderSelectBuilder.java:460)
org.hibernate.loader.ast.internal.LoaderSqlAstCreationState.visitFetches(LoaderSqlAstCreationState.java:131)
org.hibernate.sql.results.graph.collection.internal.EagerCollectionFetch.<init>(EagerCollectionFetch.java:77)
org.hibernate.metamodel.mapping.internal.PluralAttributeMappingImpl.generateFetch(PluralAttributeMappingImpl.java:390)
org.hibernate.loader.ast.internal.LoaderSelectBuilder.lambda$visitFetches$5(LoaderSelectBuilder.java:431)
java.util.ArrayList.forEach(Unknown Source)

Here is how my database is defined,

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(45) DEFAULT NULL,
  `password` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;


CREATE TABLE `users_users` (
  `user_id` int(11) NOT NULL,
  `friends_id` int(11) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
Anil Nivargi
  • 1,473
  • 3
  • 27
  • 34
  • It seems to be duplicating [How to Create Hibernate mapping for self referencing table](https://stackoverflow.com/questions/29975751/how-to-create-hibernate-mapping-for-a-self-referencing-table) – Nowhere Man Apr 19 '20 at 18:35
  • @AlexRudenko it doesn't appear to be so. What you reference applies to a paren/child entity model. I believe in this case, we are talking about peer entity model, which ends up with stack overflow because it will keep fetching peers of peers. – raminr Apr 20 '20 at 11:52
  • Here `User` has `@OneToMany List friends`, there `Employee` has `@OneToMany List subordinates` and a manager also mapped into Employee table - the difference does not appear to be huge – Nowhere Man Apr 20 '20 at 12:47

1 Answers1

0

You need to close the loop. If A is a friend of B, that means B is also a friend of A, so it will keep trying to get the friends until it throws stack overflow. Change fetch type from EAGER to LAZY.

I don't know how you are managing Hibernate Session within Struts (please include some code and configuration) but ultimately all the work you have to do has to be within a session. Regardless of the framework, this is how it typically works:

You start with a Transaction. By default the scope of your Hibernate session context is the Transaction, that means the session is closed when the transaction is committed. (you can change this. See Contextual Session) If you don't explicitly start the transaction, then Hibernate will create one for you.

If you do all your work while the session is open, then you won't run into any lazy initialization exception. I think, in your case, your solution is to start your own transaction, do the work, and then commit the transaction.

raminr
  • 784
  • 3
  • 12
  • Now it gives an exception while adding friends failed to lazily initialize a collection of role: com.javaimplant.socialnetwork.model.User.friends, could not initialize proxy - no Session org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.javaimplant.socialnetwork.model.User.friends, could not initialize proxy - no Session – Gaurav Matta Apr 19 '20 at 18:35
  • That's because you are trying to access the children entities after Hibernate has closed the session. I don't know what your transaction scope is, but if you demarcate the transaction in a wider scope, you can fetch the children entities. Are you using local transaction or JTA? What platform is this running on? JEE? Spring? – raminr Apr 19 '20 at 18:41
  • I am using Struts – Gaurav Matta Apr 20 '20 at 06:28