Gareth Lewis
Gareth Lewis

Reputation: 35

java.lang.StackOverflowError occuring with Hibernate and three tables

I'm building an application that requires that a device can send a request to a webservice asking whether it can run a Jasmine unit test. This bit works. What doesn't work, is if I ask Hibernate to retrieve a full list of data, I get a StackOverFlowError.

I've included the three entities.

@Entity
@Table(name = "device")
    public class Device {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "device_id")
    private Integer id;

    @Column(name = "device_name")
    private String deviceName;

    @OneToMany(mappedBy = "device", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private Set<Test> tests;

}

@Entity
@Table(name = "test")
public class Test {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "test_id")
    private Integer id;

    @Column(name = "test_name")
    private String testName;

    @OneToMany(mappedBy = "test", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private Set<Test_Case> testcases;

    @ManyToOne
    @JoinColumn(name = "device_id")
    private Device device;

}

@Entity
@Table(name = "test_case")
public class Test_Case {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private Integer id;

    @Column(name = "test_case_id")
    private String testCaseId;

    @Column(name = "can_run")
    private String canRun;

    @ManyToOne
    @JoinColumn(name = "test_id")
    private Test test;
}

So to reiterate. Device contains a set of Test, a Test being something like Barcode, Scanner, etc, and each Test contains a set of Test Cases. A test case being an individual test for Barcode, etc. The schema for the database looks like the following.

CREATE TABLE device (
    device_id int(11) NOT NULL AUTO_INCREMENT,
    device_name varchar(100) DEFAULT NULL,
    PRIMARY KEY(device_id)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

CREATE TABLE test(
    test_id int(11) NOT NULL AUTO_INCREMENT,
    test_name varchar(100) DEFAULT NULL,
    device_id int(11) NOT NULL,
    PRIMARY KEY(test_id),
    INDEX FK_DEVC (device_id),
    CONSTRAINT FK_DEVC FOREIGN KEY (device_id) REFERENCES device (device_id)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

CREATE TABLE test_case (
    id int(11) NOT NULL AUTO_INCREMENT,
    test_case_id varchar(100) DEFAULT NULL,
    can_run varchar(1) DEFAULT NULL,
    test_id int(11) NOT NULL,
    PRIMARY KEY(id),
    INDEX FK_TEST (test_id),
    CONSTRAINT FK_TEST FOREIGN KEY (test_id) REFERENCES test (test_id)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8;

When I ask Hibernate to retrieve everything, I get the following queries generated.

Hibernate: select device0_.device_id as device_i1_0_, device0_.device_name as device_n2_0_ from device device0_

Hibernate: select tests0_.device_id as device_i3_0_1_, tests0_.test_id as test_id1_2_1_, tests0_.test_id as test_id1_2_0_, tests0_.device_id as device_i3_2_0_, tests0_.test_name as test_nam2_2_0_ from test tests0_ where tests0_.device_id=?

Hibernate: select testcases0_.test_id as test_id4_2_1_, testcases0_.id as id1_3_1_, testcases0_.id as id1_3_0_, testcases0_.can_run as can_run2_3_0_,testcases0_.test_id as test_id4_3_0_, testcases0_.test_case_id as test_cas3_3_0_ from test_case testcases0_ where testcases0_.test_id=?

This causes a StackOverflow when the results are being generated, and after looking over the code for a few days and following advice from other answers, I just cannot get this to stop producing that error.

The call is being generated by a Spring MVC Restful interface that sends response body back using Jackson to convert the output to JSON.

Is there anything obvious that I am doing wrong here? For those interested, I'm using Spring 3.2.7, Hibernate 4.2.8 and MySQL 5.something.

Upvotes: 0

Views: 1204

Answers (1)

Steven Pessall
Steven Pessall

Reputation: 993

The serialization by Jackson is running in circles. When serializing the Test Jackson also serializes Test_Case objects. But to serialize a Test_Case Jackson also tries to serialize the Test object.

You can add a @JsonIgnore annotation to the member test in Test_Case to break this circle.

The member device in the class Test also needs the @JsonIgnore annotation.

Upvotes: 1

Related Questions