stevecross
stevecross

Reputation: 5684

Hibernate StackOverflowError

I am trying to create a many-to-many relationship between two Hibernate entities. This are my entities:

Supplier:

package domain;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

@Entity
@Table(name = "supplier")
public class Supplier implements Serializable {

    private static final long serialVersionUID = -8770635537770426413L;

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

    @Column(name = "id")
    private int id;

    @ManyToMany(cascade = { CascadeType.ALL })
    @JoinTable(name = "supplier_project", joinColumns = { @JoinColumn(name = "supplier_name") }, inverseJoinColumns = { @JoinColumn(name = "project_name") })
    private Set<Project> projects = new HashSet<>();

    @ManyToMany(cascade = { CascadeType.ALL })
    @JoinTable(name = "supplier_cad_system", joinColumns = { @JoinColumn(name = "supplier_name") }, inverseJoinColumns = { @JoinColumn(name = "cad_system_name") })
    private Set<CadSystem> cadSystems = new HashSet<>();

    public Supplier() {
    }

    public Supplier(final String name, final int id) {
        this.name = name;
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(final String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

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

    public Set<Project> getProjects() {
        return projects;
    }

    public void setProjects(final Set<Project> projects) {
        this.projects = projects;
    }

    public Set<CadSystem> getCadSystems() {
        return cadSystems;
    }

    public void setCadSystems(final Set<CadSystem> cadSystems) {
        this.cadSystems = cadSystems;
    }

    @Override
    public String toString() {
        final StringBuilder builder = new StringBuilder("Supplier[name=");
        builder.append(name);
        builder.append(", id=");
        builder.append(id);
        builder.append(", projects=");
        builder.append(projects);
        builder.append(", cadSystems=");
        builder.append(cadSystems);
        builder.append("]");

        return builder.toString();
    }

}

CadSystem:

package domain;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

@Entity
@Table(name = "cad_systems")
public class CadSystem implements Serializable {

    private static final long serialVersionUID = -777117867924204408L;

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

    @ManyToMany(mappedBy = "cadSystems")
    private Set<Supplier> suppliers = new HashSet<>();

    public CadSystem() {
    }

    public CadSystem(final String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(final String name) {
        this.name = name;
    }

    public Set<Supplier> getSuppliers() {
        return suppliers;
    }

    public void setSuppliers(final Set<Supplier> suppliers) {
        this.suppliers = suppliers;
    }

    @Override
    public String toString() {
        final StringBuilder builder = new StringBuilder("CadSystem[name=");
        builder.append(name);
        builder.append(", suppliers=");
        builder.append(suppliers);
        builder.append("]");

        return builder.toString();
    }

}

Project:

package domain;

import java.io.Serializable;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

@Entity
@Table(name = "project")
public class Project implements Serializable {

    private static final long serialVersionUID = 5652106258971634091L;

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

    @ManyToMany(mappedBy = "projects")
    private Set<Supplier> suppliers;

    public Project() {
    }

    public Project(final String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(final String name) {
        this.name = name;
    }

    public Set<Supplier> getSuppliers() {
        return suppliers;
    }

    public void setSuppliers(final Set<Supplier> suppliers) {
        this.suppliers = suppliers;
    }

    @Override
    public String toString() {
        final StringBuilder builder = new StringBuilder("Project[name=");
        builder.append(name);
        builder.append("]");

        return builder.toString();
    }

}

Sadfully I get a StackOverflowError:

Sep 17, 2014 3:10:14 PM org.hibernate.annotations.common.reflection.java.JavaReflectionManager <clinit>
INFO: HCANN000001: Hibernate Commons Annotations {4.0.5.Final}
Sep 17, 2014 3:10:14 PM org.hibernate.Version logVersion
INFO: HHH000412: Hibernate Core {4.3.6.Final}
Sep 17, 2014 3:10:14 PM org.hibernate.cfg.Environment <clinit>
INFO: HHH000206: hibernate.properties not found
Sep 17, 2014 3:10:14 PM org.hibernate.cfg.Environment buildBytecodeProvider
INFO: HHH000021: Bytecode provider name : javassist
Sep 17, 2014 3:10:14 PM org.hibernate.cfg.Configuration configure
INFO: HHH000043: Configuring from resource: /hibernate.cfg.xml
Sep 17, 2014 3:10:14 PM org.hibernate.cfg.Configuration getConfigurationInputStream
INFO: HHH000040: Configuration resource: /hibernate.cfg.xml
Sep 17, 2014 3:10:14 PM org.hibernate.cfg.Configuration doConfigure
INFO: HHH000041: Configured SessionFactory: null
Sep 17, 2014 3:10:36 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
WARN: HHH000402: Using Hibernate built-in connection pool (not for production use!)
Sep 17, 2014 3:10:36 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH000401: using driver [com.microsoft.sqlserver.jdbc.SQLServerDriver] at URL [jdbc:sqlserver://****;databaseName=****]
Sep 17, 2014 3:10:36 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH000046: Connection properties: {user=****, password=****}
Sep 17, 2014 3:10:36 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH000006: Autocommit mode: false
Sep 17, 2014 3:10:36 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
INFO: HHH000115: Hibernate connection pool size: 10 (min=1)
Sep 17, 2014 3:10:37 PM org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.SQLServer2005Dialect
Sep 17, 2014 3:10:37 PM org.hibernate.engine.transaction.internal.TransactionFactoryInitiator initiateService
INFO: HHH000399: Using default transaction strategy (direct JDBC transactions)
Sep 17, 2014 3:10:37 PM org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory <init>
INFO: HHH000397: Using ASTQueryTranslatorFactory
Hibernate: 
    select
        supplier0_.name as name1_2_0_,
        supplier0_.id as id2_2_0_ 
    from
        supplier supplier0_ 
    where
        supplier0_.name=?
Hibernate: 
    select
        projects0_.supplier_name as supplier1_2_0_,
        projects0_.project_name as project_2_4_0_,
        project1_.name as name1_1_1_ 
    from
        supplier_project projects0_ 
    inner join
        project project1_ 
            on projects0_.project_name=project1_.name 
    where
        projects0_.supplier_name=?
Hibernate: 
    select
        cadsystems0_.supplier_name as supplier1_2_0_,
        cadsystems0_.cad_system_name as cad_syst2_3_0_,
        cadsystem1_.name as name1_0_1_ 
    from
        supplier_cad_system cadsystems0_ 
    inner join
        cad_systems cadsystem1_ 
            on cadsystems0_.cad_system_name=cadsystem1_.name 
    where
        cadsystems0_.supplier_name=?
Hibernate: 
    select
        suppliers0_.cad_system_name as cad_syst2_0_0_,
        suppliers0_.supplier_name as supplier1_3_0_,
        supplier1_.name as name1_2_1_,
        supplier1_.id as id2_2_1_ 
    from
        supplier_cad_system suppliers0_ 
    inner join
        supplier supplier1_ 
            on suppliers0_.supplier_name=supplier1_.name 
    where
        suppliers0_.cad_system_name=?
Exception in thread "main" java.lang.StackOverflowError
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:316)
    at java.lang.String.valueOf(String.java:2854)
    at java.lang.StringBuilder.append(StringBuilder.java:128)
    at domain.CadSystem.toString(CadSystem.java:59)
    at java.lang.String.valueOf(String.java:2854)
    at java.lang.StringBuilder.append(StringBuilder.java:128)
    at java.util.AbstractCollection.toString(AbstractCollection.java:450)
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:317)
    at java.lang.String.valueOf(String.java:2854)
    at java.lang.StringBuilder.append(StringBuilder.java:128)
    at domain.Supplier.toString(Supplier.java:91)
    at sun.reflect.GeneratedMethodAccessor5.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:196)
    at domain.Supplier_$$_jvste67_0.toString(Supplier_$$_jvste67_0.java)
    at java.lang.String.valueOf(String.java:2854)
    at java.lang.StringBuilder.append(StringBuilder.java:128)
    at java.util.AbstractCollection.toString(AbstractCollection.java:450)

I try to get a Supplier object using this command: session.load(Supplier.class, "key"). If I comment out all CadSystem stuff it works. And even storing a Supplier object with added CadSystems works. I think all tables are set up correctly. Why do I get this error?

Upvotes: 2

Views: 4560

Answers (5)

hpk_the_goat
hpk_the_goat

Reputation: 11

Kind of off topic but...

In case anyone gets this error in relation to lombak (Spring JPA), Just create your own toString method.

Upvotes: 1

Jagadeesh
Jagadeesh

Reputation: 852

Solution is very simple, try to run your program by removing toString() method from all classes. It is causing infinite looping.

Upvotes: 1

Wundwin Born
Wundwin Born

Reputation: 3475

Infinite recurrsion between CadSystem#toString() and Supplier#toString() make StackOverflowError.

To avoid this error, toString() of relevant Entity should include only id, name or/and other appropriate property info of related entity.

Like this example in CadSystem#toString(),

for (Supplier supplier : suppliers) {
    builder.append("Supplier :[Id=" + supplier.getId() +
                              ", Name=" + supplier.getName() + "]\n");
}

Upvotes: 3

stevecross
stevecross

Reputation: 5684

I created an infinite recursion between Supplier#toString() and CadSystem#toString(). Supplier#toString() called CadSystem#toString() and CadSystem#toString() called Supplier#toString() again. Thus the methods could never terminate resulting in a StackOverflowError.

Upvotes: 0

Vineet Kasat
Vineet Kasat

Reputation: 1014

Exception is coming while appending to string builder

at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:316) at java.lang.String.valueOf(String.java:2854) at java.lang.StringBuilder.append(StringBuilder.java:128)

Stack Overflow comes when thread stack runs out of space to hold more variables. In the below code, builder is a local variable which gets stored on stack and you append suppliers to it. Increase your thread stack size or check the value of suppliers, this may be large.

builder.append(name);
        builder.append(", suppliers=");
        builder.append(suppliers);
        builder.append("]");

Upvotes: 0

Related Questions