Direct self-reference leading to cycle exception

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

2

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 above

then 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

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

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

You Might Also Like