Could not write JSON: Infinite recursion (StackOverflowError); nested exception spring boot

前端 未结 7 1291
时光说笑
时光说笑 2020-12-08 23:18

This is my District Controller, when I try to fetch data after saving I get the error, even when I try get object form getDistrict(Long id) the same strikes ple

相关标签:
7条回答
  • 2020-12-08 23:39

    You are facing this issue because the Statemaster model contains the object of Districtmaster model, which itself contains the object of Statemaster model. This causes an infinite json recursion.

    You can solve this issue by 3 methods.

    1 - Create a DTO and include only the fields that you want to display in the response.

    2 - You can use the @JsonManagedReference and @JsonBackReference annotations.

    E.g. Add the @JsonManagedReference annotation to the Statemaster model.

    @JsonManagedReference
    @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="statemaster")
    public Set<Districtmaster> getDistrictmasters() {
        return this.districtmasters;
    }
    

    Add the @JsonBackReference annotation to the Districtmaster model.

    @JsonBackReference
    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="district_of_state")
    public Statemaster getStatemaster() {
        return this.statemaster;
    }
    

    3 - You can use the @JsonIgnore annotation on the getter or setter method.

    @JsonIgnore
    @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="statemaster")
    public Set<Districtmaster> getDistrictmasters() {
        return this.districtmasters;
    }
    

    However, this approach will omit the set of Districtmaster from the response.

    0 讨论(0)
  • 2020-12-08 23:47

    @JsonBackReference and @JsonManagedReference didn't work for me since I was using a class that represented a join table and the only way to get it to work was to put the @JsonBackReference above the fields representing the linked classes. The net effect was that if I was pulling a record from the join class using JSON, none of the join fields would show up, making the returned information useless.

    I'd give examples but I like to avoid long replies. @JsonIdentityInfo explained in the article below provides a short, simple but highly efficient solution.

    Bidirectional relationships and InfiniteRecursion

    0 讨论(0)
  • 2020-12-08 23:48

    In the Statemaster class make districtmasters a List<Districtmaster> instead of Set<Districtmaster> and change the getter method accordingly: public List<Districtmaster> getDistrictmasters(). Unfortunately I can not explain why, but this worked for me.

    0 讨论(0)
  • 2020-12-08 23:49

    Looks like your problem is Hibernate relations. When you try to serialize the entity Statemaster the serializer calls serialization of the Districtmaster set which in turn somehow reference the Statemaster again.

    There are two possible ways to solve:

    1. Unproxy object
    2. Create DTO (Data Transfer Object) - kind of copy of your entity where all necessary fields should be assigned and return the DTO.
    0 讨论(0)
  • 2020-12-08 23:50

    I've been struggling with the same problem for days, I tried @JsonIgnore, @JsonManagedReference and @JsonBackReference annotation, and even @JsonIdentityInfo annotation and none of them have worked.

    If you (the future readers ) are in the same situation, the solution is easier than you expected, simply put @JsonIgnore or @JsonManagedReference / @JsonBackReference on the attribute's getter and not on the attribute itself. And that will do.

    Here's a simple example how to do so :

    Say we have two classes, Order and Product, and OneToMany relation between them.

    Order class

    public class Order{
      @Id
      @GeneratedValue(strategy = GenerationType.AUTO)
      private String id_order;
      private double price;
      @OneToMany(mappedBy = "order")
      @LazyCollection(LazyCollectionOption.FALSE)
      private List<Product> products
      //constructor, getters & setter 
    }
    

    Product Class:

    public class Product{
       @Id
       @GeneratedValue(strategy = GenerationType.AUTO)
       private String id_product;
       private String name;
       @ManyToOne
       @JoinColumn(name = "id_order")
       private Order order;
       //consturctor, getters & setters
     }
    

    So in order to use @JsonManagedReference and @JsonBackReference, just add them to the getters as the following :

    public class Order{
      @Id
      @GeneratedValue(strategy = GenerationType.AUTO)
      private String id_order;
      private double price;
      @OneToMany(mappedBy = "order")
      @LazyCollection(LazyCollectionOption.FALSE)
      private List<Product> products
      //constructor, getters & setter 
      @JsonManagedReference
      public List<Product> getProducts(){
        return products;
    }
    

    Product class:

    public class Product{
      @Id
      @GeneratedValue(strategy = GenerationType.AUTO)
      private String id_product;
      private String name;
      @ManyToOne
      @JoinColumn(name = "id_order")
      private Order order;
      //consturctor, getters & setters
      @JsonBackReference
      public Order getOrder(){
        return order;
      }
     }
    
    0 讨论(0)
  • 2020-12-08 23:51

    That's because for Statemaster in json the set of Districtmaster's is put. And each Districtmaster has the Statemaster in itself, so it's also put into the json. So that you get the infinite recursion

        @JsonIgnore
        @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, 
        mappedBy="statemaster")
        public Set<Districtmaster> getDistrictmasters() {
            return this.districtmasters;
        }
    

    Adding @JsonIgnore annotation on Set<Districtmaster> will prevent that recursion. You can put the @JsonIgnore at public Statemaster getStatemaster() either.

    0 讨论(0)
提交回复
热议问题