I have a class; something like the following:
public abstract class ElasticSearchValue<T> { private Long txId; private Long currentTxId; private T previous; public Long getTxId() { return txId; } public void setTxId(Long txId) { this.txId = txId; } public Long getCurrentTxId() { return currentTxId; } public void setCurrentTxId(Long currentTxId) { this.currentTxId = currentTxId; } public Object getPrevious() { return previous; } public void setPrevious(T previous) { this.previous = previous; }
}And a class that extends the class above
public class DailyActivity extends ElasticSearchValue<DailyActivity> { Long agentId; Date date; Long success; public Long getAgentId() { return agentId; } public void setAgentId(Long agentId) { this.agentId = agentId; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } public Long getSuccess() { return success; } public void setSuccess(Long success) { this.success = success; } @Override public String toString() { return agentId + "_" + date.toString(); }
}Now, I have an object of type DailyActivity, and when I try to convert it into a JSON string, I get the following exception:
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Direct self-reference leading to cycle (through reference chain: com.pr.analysis.DailyActivity["previous"])
I have looked for solution on google but the solution which I get asks to put jsonIgnore to previous value which is not what I intent to do. Has anyone faced the same issue?
Thanks
EDITI know there is a cycle in the class and I am asking how to deserialize the class which has a self reference?
6 Answers
In this case you need to annotate the relationships with @JsonManagedReference and @JsonBackReference like this:
@ManyToOne @JoinColumn(name = "company_id", referencedColumnName = "id") @JsonBackReference private Company company And
@OneToMany(mappedBy="company") @JsonManagedReference private Set<Employee> employee = new HashSet<Employee>();There is a nice example here
SerializationFeature has a property called FAIL_ON_SELF_REFERENCES default is true but you can set to false to skip this kind of exception.
ObjectMapper objectMapper = new ObjectMapper(); objectMapper.configure(SerializationFeature.FAIL_ON_SELF_REFERENCES, false);If you are using SpringBoot you can simply add spring.jackson.serialization.fail-on-self-references=false in your application.properties
The self-reference is here:
public class DailyActivity extends ElasticSearchValue<DailyActivity> {You're saying DailyActivity is an ElasticSearchValue<DailyActivity>, which is by itself an ElasticSearchValue<ElasticSearchValue<DailyActivity>>, and this goes on infinitely...
Update: I would break that in two classes. Create DailyActivity without subclassing ElasticSearchValue:
public class DailyActivity { // the same content as your class abovethen create another class like:
public class ElacticDailyActivity extends ElasticSearchValue<DailyActivity> { 1 Try @JsonIdentityInfo annotation as given in this example. More details here
@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="@id")
public class Identifiable
{ public int value; public Identifiable next;
} 1 Please refer to related question and a sensible way of handling this in my opinion.
In current case it would help to annotate 'previous' like below
@JsonIgnoreProperties({"previous"})//... along with other annotations
private T previous; I guess somewhere in your code. The previous of some instance of DailyActivity point to itself.
2