1

I have my DB tables designed like below.

With this structure, using Springboot, I am not able to fetch all child elements of TABLE-1 till TABLE-3

enter image description here

Below are the Entity classes for the same

TABLE-1 (SDKMainCollection.java)

@Entity
@Table(name="sdkmaincollection")
public class SDKMainCollection {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;
    private String sdkgroupname;
    @JsonIgnore
    @OneToMany(mappedBy = "sdkcollectionobj", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private Set<SDKCollection> sdkcollection;

    public SDKMainCollection() {
    }

    public SDKMainCollection(int id,String sdkGroupName) {
        this.id= id;
        this.sdkgroupname =sdkGroupName;
    }

    public SDKMainCollection(String sdkGroupName) {
        this.sdkgroupname =sdkGroupName;
    }
    //Getters and Setters
}

TABLE-2 (SDKCollection.java)

@Entity
@Table(name="sdkcollection")
public class SDKCollection {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;
    private String sdktitle;
    private String sdkid;
    private String sdkresourceid;
    private String sdkdescription;
    private String sdkimageName;
    @JsonIgnore
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "sdkmaincollection_id")
    private SDKMainCollection sdkcollectionobj;
    @JsonIgnore
    @OneToMany(mappedBy = "sdkcolsubobj", cascade = CascadeType.ALL, fetch=FetchType.LAZY) 
    private Set<Ads> ads;

    public SDKCollection() {
    }
    public SDKCollection(int id, String sdkTitle, String sdkId, String sdkresourceId, String sdkdescription,
            String sdkimageName,SDKMainCollection sdkObj) {
        this.id = id;
        this.sdktitle = sdkTitle;
        this.sdkid = sdkId;
        this.sdkresourceid = sdkresourceId;
        this.sdkdescription = sdkdescription;
        this.sdkimageName = sdkimageName;
        this.sdkcollectionobj = sdkObj;
    }
    public SDKCollection(String sdkTitle, String sdkId, String sdkresourceId, String sdkdescription,
            String sdkimageName,SDKMainCollection sdkObj) {

        this.sdktitle = sdkTitle;
        this.sdkid = sdkId;
        this.sdkresourceid = sdkresourceId;
        this.sdkdescription = sdkdescription;
        this.sdkimageName = sdkimageName;
        this.sdkcollectionobj = sdkObj;
    }
    //Getters and Setters
}

TABLE-3 (Ads.java)

@Entity
@Table(name="ads")
public class Ads {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;
    private String adtitle;
    private String adtag;
    private String adtype;
    private String imagename;
    private String controlid;
    @JsonIgnore
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "sdkcollection_id")
    private SDKCollection sdkcolsubobj;

    public Ads() {

    }
    public Ads(int id, String adTitle, String adTag, String adType, String imageName, String controlID,
            SDKCollection sdkcollection     
            ) {
        this.id = id;
        this.adtitle = adTitle;
        this.adtag = adTag;
        this.adtype = adType;
        this.imagename = imageName;
        this.controlid = controlID;
        this.sdkcolsubobj = sdkcollection;
    }
    public Ads(String adTitle, String adTag, String adType, String imageName, String controlID
            ,SDKCollection sdkcollection) {
        this.adtitle = adTitle;
        this.adtag = adTag;
        this.adtype = adType;
        this.imagename = imageName;
        this.controlid = controlID;
        this.sdkcolsubobj = sdkcollection;
    }
    //Getters and Setters
}

And below is my controller class for fetching elements

@RestController
@RequestMapping("/api/sdk/")
@CrossOrigin
public class GetSDKController {
    @Autowired
    private SDKMainCollectionRepo sdkMainCollectionRepo;
    @Autowired
    private SDKCollectionRepo sdkCollectionRepo;
    @Autowired
    private AdsRepo adsRepo;
    @GetMapping("/getAllSDKs")
    public List<SDKMainCollection> getAllSDK(){
        sdkDataMapper = new SDKDataMapper(sdkMainCollectionRepo,sdkCollectionRepo,adsRepo);
        List<SDKMainCollection> totalResp  = (List<SDKMainCollection>) sdkMainCollectionRepo.findAll();
        System.out.println("getAllSDK = totalResp "+totalResp);

        //NOT GETTING WHAT IS EXPECTED

        return totalResp;
    }
}

Below is my expectation , but I am getting Stackoverflow error

enter image description here

Stackoverflow Error Logs:

java.lang.StackOverflowError: null
    at java.util.AbstractCollection.toString(Unknown Source) ~[na:1.8.0_131]
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:328) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
    at java.lang.String.valueOf(Unknown Source) ~[na:1.8.0_131]
    at java.lang.StringBuilder.append(Unknown Source) ~[na:1.8.0_131]
    at com.dvservices.models.SDKMainCollection.toString(SDKMainCollection.java:59) ~[classes/:na]
    at java.lang.String.valueOf(Unknown Source) ~[na:1.8.0_131]
    at java.lang.StringBuilder.append(Unknown Source) ~[na:1.8.0_131]
    at com.dvservices.models.SDKCollection.toString(SDKCollection.java:118) ~[classes/:na]
    at java.lang.String.valueOf(Unknown Source) ~[na:1.8.0_131]
    at java.lang.StringBuilder.append(Unknown Source) ~[na:1.8.0_131]
    at java.util.AbstractCollection.toString(Unknown Source) ~[na:1.8.0_131]
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:328) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
    at java.lang.String.valueOf(Unknown Source) ~[na:1.8.0_131]
    at java.lang.StringBuilder.append(Unknown Source) ~[na:1.8.0_131]
    at com.dvservices.models.SDKMainCollection.toString(SDKMainCollection.java:59) ~[classes/:na]
    at java.lang.String.valueOf(Unknown Source) ~[na:1.8.0_131]
    at java.lang.StringBuilder.append(Unknown Source) ~[na:1.8.0_131]
    at com.dvservices.models.SDKCollection.toString(SDKCollection.java:118) ~[classes/:na]
    at java.lang.String.valueOf(Unknown Source) ~[na:1.8.0_131]
    at java.lang.StringBuilder.append(Unknown Source) ~[na:1.8.0_131]
    at java.util.AbstractCollection.toString(Unknown Source) ~[na:1.8.0_131]
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:328) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
    at java.lang.String.valueOf(Unknown Source) ~[na:1.8.0_131]
    at java.lang.StringBuilder.append(Unknown Source) ~[na:1.8.0_131]
    at com.dvservices.models.SDKMainCollection.toString(SDKMainCollection.java:59) ~[classes/:na]
    at java.lang.String.valueOf(Unknown Source) ~[na:1.8.0_131]
    at java.lang.StringBuilder.append(Unknown Source) ~[na:1.8.0_131]
    at com.dvservices.models.SDKCollection.toString(SDKCollection.java:118) ~[classes/:na]
    at java.lang.String.valueOf(Unknown Source) ~[na:1.8.0_131]
    at java.lang.StringBuilder.append(Unknown Source) ~[na:1.8.0_131]
    at java.util.AbstractCollection.toString(Unknown Source) ~[na:1.8.0_131]
    at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:328) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]

I guess the problem might be with getting last array and causing Stackoverflow error.

EDIT:

Is this problem due to having both OneToMany and ManyToOne in same SDKCollection class as it comes in middle of the hierarchy?

public class SDKCollection {

       ........
       @JsonIgnore
       @ManyToOne(fetch = FetchType.LAZY)
       @JoinColumn(name = "sdkmaincollection_id")
       private SDKMainCollection sdkcollectionobj;

       @JsonIgnore
       @OneToMany(mappedBy = "sdkcolsubobj", cascade = CascadeType.ALL, fetch=FetchType.LAZY) 
       private Set<Ads> ads;
Sreehari
  • 5,621
  • 2
  • 25
  • 59

5 Answers5

1

you are missing @JsonBackReference annotation thats why you're getting stackoverflow error,.@JsonIgnore is not designed to solve the Infinite Recursion problem, it just ignores the annotated property from being serialized or deserialized.

where to add

  1. in SDKCollection.java private SDKMainCollection sdkcollectionobj; back reference to SDKMaincollection,
  2. in Ads.java private SDKCollection sdkcolsubobj back reference to SDKCollection

above both should be annotated with @JsonBackReference hope it helps.

SandOfTime
  • 692
  • 6
  • 15
0
@JsonIgnore
@OneToMany(mappedBy = "sdkcolsubobj", cascade = CascadeType.ALL, fetch=FetchType.LAZY) 
private Set<Ads> ads

try fetch=FetchType.EAGER

SandOfTime
  • 692
  • 6
  • 15
  • Sorry for miss communication, I am getting a Stackoverflow error with both EAGER and LAZY. It does not gets back any data – Sreehari Apr 03 '19 at 09:37
0

Well, you are annotating the ads field with @JsonIgnore, so when it gets serialized to be sent back to the HTTP client the Jackson Serializer is ignoring it, so if you want to include ads field remove the @JsonIgnore

Also as a workaround annotate your controller by @Transaction, so that you don't get lazy initialization exception. (fetch=FetchType.EAGER is considered a bad practice see https://vladmihalcea.com/eager-fetching-is-a-code-smell/)

A better solution is to make use of an Entity graph as a fetching plan, and it integrates really well with Spring DATA, have a look at Spring Data JPA And NamedEntityGraphs

Z.yassine
  • 186
  • 1
  • 2
  • 10
  • Sorry for miss communication, I am getting a Stackoverflow error with both EAGER and LAZY. It does not gets back any data – Sreehari Apr 03 '19 at 09:36
  • Ok no problem! well, you have in your controller System.out.println("getAllSDK = totalResp "+totalResp); so the toString() of totalResp gets called and it calls each of SDKMainCollection in the List, the toString() of SDKMainCollection calls each of its field's toString() as well.. and the parents toString() get called back.. so infinite number of toString() method calls.. it is discussed here https://stackoverflow.com/questions/3593893/why-im-getting-stackoverflowerror – Z.yassine Apr 03 '19 at 11:26
0

there might be a case(s).

  1. in you condition try with fetch=FetchType.EAGER
  2. check you have data in database (also foreign key relation) or not.
piet.t
  • 11,718
  • 21
  • 43
  • 52
Arun Kumar
  • 340
  • 2
  • 15
0

So finally I was able to resolve the error.

As I had three level hierarchy, this was the only way I could make this work.

  • Removed ManyToOne from child table entities
  • Only kept cascade = CascadeType.ALL,orphanRemoval = true in @OneToMany
  • No parent table was referred with @ManyToOne from child tables

So the change was as follows

TABLE-1 (SDKMainCollection.java)

@Entity
@Table(name="sdkmaincollection")
public class SDKMainCollection {

...
...
@OneToMany(cascade = CascadeType.ALL,orphanRemoval = true)
private List<Sdkcollection> sdkCollection = new ArrayList<Sdkcollection>();

//No Constructor required
//Kept only getters and setters
}

TABLE-2 (SDKCollection.java)

@Entity
@Table(name="sdkcollection")
public class SDKCollection {

...
...
@OneToMany(cascade = CascadeType.ALL,orphanRemoval = true)
private List<Ads> ads = new ArrayList<Ads>();

//No parent table with @ManyToOne was refered
//No Constructor required
//Kept only getters and setters

}

TABLE-3 (Ads.java)

@Entity
@Table(name="ads")
public class Ads {


...
...
//No parent table with @ManyToOne was refered
//No Constructor required
//Kept only getters and setters

}

Hibernate made relation and extra tables for the hierarchy. Child table details at last level was retrieved without any Stackoverflowerror.

Sreehari
  • 5,621
  • 2
  • 25
  • 59