Can not handle managed/back reference 'defaultReference': back reference type (java.util.List) not compatible with managed type (ForumAnswerReplay)
Asked Answered
T

4

14

Forum Answer saving time facing issue.before i saved successfully using @JsonIgnore but now i removed @JsonIgnore annonation.and added @JsonBackReference and @JsonManagedReference.

Stack Trace

java.lang.IllegalArgumentException: Can not handle managed/back reference 'defaultReference': back reference type (java.util.List) not compatible with managed type (com.tta.abcd.model.ForumAnswerReplay)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase._resolveManagedReferenceProperty(BeanDeserializerBase.java:790)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.resolve(BeanDeserializerBase.java:516)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:296)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244)
at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142)
at com.fasterxml.jackson.databind.DeserializationContext.findContextualValueDeserializer(DeserializationContext.java:443)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.createContextual(CollectionDeserializer.java:196)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.createContextual(CollectionDeserializer.java:26)
at com.fasterxml.jackson.databind.DeserializationContext.handleSecondaryContextualization(DeserializationContext.java:681)
at com.fasterxml.jackson.databind.DeserializationContext.findContextualValueDeserializer(DeserializationContext.java:445)
at com.fasterxml.jackson.databind.deser.std.StdDeserializer.findDeserializer(StdDeserializer.java:967)

Forum.java

    @Entity
    @Table(name="Forum")
    public class Forum {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name="forumId")
    private Long forumId;

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

    @Column(columnDefinition="varchar(1000)",name="discription")
    private String discription;

    @Column(name="postedDate")
    private Date postedDate;

    @Fetch(value = FetchMode.SELECT)
    @OneToMany(cascade = CascadeType.ALL)
    @JoinColumn(name = "forumId")
    @JsonIgnore
    private List<ForumAnswer> forumList;
    }

ForumAnswer.java

    @Entity
    @Table(name="ForumAnswer")
    public class ForumAnswer {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name="forumAnswerId")
    private Long forumAnswerId;

    @ManyToOne
        @JoinColumn(name = "forumId",insertable=true, updatable=true,nullable=true)
    private Forum forum;

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

    @Column(name="answerDate")
    private Date answerDate;

    @Fetch(value = FetchMode.SELECT)
    @OneToMany(cascade = CascadeType.ALL)
    @JoinColumn(name = "forumAnswerId")
    @JsonBackReference
    private List<ForumAnswerReplay> forumAnswerReplayList;

    @Transient
    private List<ForumAnswerReplay> faqReplayList;
}

ForumAnswerReplay.java

@Entity
@Table(name="ForumAnswerReplay")
public class ForumAnswerReplay {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name="replayId")
    private Long replayId;

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

    @Column(name="replayToAnswerDate")
    private Date replayToAnswerDate;


    @ManyToOne(fetch=FetchType.EAGER)
    @JoinColumn(name="forumAnswerId",insertable=true,updatable=true,nullable=true)
        @JsonManagedReference
    private ForumAnswer forumAnswer;

    @Transient
    private String message;
}

Controller Code:

public ForumAnswer saveForumAns(@RequestBody ForumAnswer forumAns, BindingResult bindingResult, HttpSession session,
        HttpServletRequest request, HttpServletResponse response) {
    ForumAnswer forumDetails = forumService.saveForumAns(forumAns, bindingResult, session);
    if (forumDetails != null) {
        forumDetails.setMessage("success");
    }
    else {
        forumDetails.setMessage("failed");
    }
    return forumDetails;
}

DAO:

public ForumAnswer saveForumAns(ForumAnswer forumAns, BindingResult bindingResult) {

    final Session session = getSession();
    try {
        session.beginTransaction();
        Query query = session.createQuery("UPDATE ForumAnswer set answer =:answer,"
                + "forumAnswerId =:forumAnswerId,farmerUuid =:farmerUuid, answerDate =:answerDate");
        query.setParameter("answer", forumAns.getAnswer());
        query.setParameter("forumAnswerId", forumAns.getForumAnswerId());
        query.setParameter("farmerUuid", forumAns.getFarmer());
        query.setParameter("answerDate", forumAns.getAnswerDate());
        session.merge(forumAns);
        session.getTransaction().commit();
    } catch (Exception e) {
        e.printStackTrace();
        System.out.println("error while saving forum details" + e);
    } finally {
        session.close();
    }

    return forumAns;
}
Thea answered 23/6, 2017 at 5:42 Comment(0)
S
27

I think you have misplaced @JsonManagedReference and @JsonBackReference.

@JsonManagedReference : its forward part of reference so it will apply on collection type.

@JsonBackReference: its back part of reference.

so your code must be like

  @JsonManagedReference 
     private List<ForumAnswerReplay> forumAnswerReplayList;

 @JsonBackReference
    private ForumAnswer forumAnswer;

you can also use @JsonIdentityInfo you have to apply

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, 
                  property  = "forumAnswerId", 
                  scope     = Long.class)
public class ForumAnswer {
}

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, 
                  property  = "replyId", 
                  scope     = Long.class)
public class ForumAnswerReplay {
}
Smithsonite answered 23/6, 2017 at 6:25 Comment(5)
thank you for your replay. in properties level instead of @JsonManagedReference i'm using @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "forumAnswerId") but not working.same issue i'm facing.Thea
@umapati: you have to remove @JsonManagedReference and @JsonBackReference and add @JsonIdentityInfo on both class.Smithsonite
i removed both annotations and i added @JsonIdentityInfo class level. now data is saving successfully but retrieving time data not reaching to ui.Thea
you have only posted code for save. update your question and write code you tried for retrieval.Smithsonite
So @JsonBackReference goes only with @ManyToOne and @JsonManagedReference goes only with @OneToMany ?Calvo
I
6

Remove @JsonManagedReference in ForumAnswer class.

ForumAnswer class:

@Fetch(value = FetchMode.SELECT)
    @OneToMany(cascade = CascadeType.ALL,fetch=FetchType.EAGER)
    @JoinColumn(name = "forumAnswerId")
    private List<ForumAnswerReplay> forumAnswerReplayList;

In ForumAnswerReplay:

@JsonBackReference
public ForumAnswer getForumAnswer() {
    return forumAnswer;
}
Idellaidelle answered 23/6, 2017 at 9:36 Comment(0)
B
5

Use @JsonBackReference for @OneToMany and @JsonManagedReference for @ManyToOne relation to allow Jackson to better handle the relation.

Berliner answered 3/1, 2018 at 12:57 Comment(4)
What about @ManyToMany?Lionfish
If you only want to avoid recursion, you can use @JsonIdentityInfo for Parent class. You can see baeldung.com/… for further clarification. Thank you!Berliner
Everyone links to that one "tutorial" at 'baeldung', but it doesn't really explain anything.Cistercian
\@JsonBackReference goes on the child, the non-collection \@ManyToOne. fasterxml.github.io/jackson-annotations/javadoc/2.11/com/… \@JsonManagedReference goes on the parent, the\@OneToMany collectionMartinamartindale
R
1

I had a similar issue recently, I tried to debug the code, I searched all around the internet and what helped finally was this:

Make sure you set your @JsonBackReference and @JsonManagedReference to have a unique value, for instance in my Department class I have:

    @JsonManagedReference(value = "faculty-department")
    @OneToMany(mappedBy = "department")
    private List<Faculty> faculties;

and in my Faculty class, I have:

    @JsonBackReference(value = "faculty-department")
    @ManyToOne
    private Department department;

When working on a project with just two entities, I noticed that the code was OK, but when the code base grew to more than 5 entities. This error tends to occur if you have multiple relationships with more than one @JsonBackReference in the same entity/class.

If the code builds successfully you may still get a 415 media unsupported error even if you select application/json as your content type while posting, so you will have to set the value as a unique key shared across related entities.

Using SpringBoot 3.1.1 at the time of this answer.

Robena answered 6/7, 2023 at 1:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.