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;

5 Answers 5

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.

Sign up to request clarification or add additional context in comments.

Comments

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

try fetch=FetchType.EAGER

1 Comment

Sorry for miss communication, I am getting a Stackoverflow error with both EAGER and LAZY. It does not gets back any data
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

2 Comments

Sorry for miss communication, I am getting a Stackoverflow error with both EAGER and LAZY. It does not gets back any data
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 stackoverflow.com/questions/3593893/…
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.

Comments

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.

3 Comments

Sorry for miss communication, I am getting a Stackoverflow error with both EAGER and LAZY. It does not gets back any data
I crossed checked my DB, its having FK relation set up properly
it may be due to toString() method. Please check it may be repeating class properties.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.