Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

EDIT I know there is a cycle in the class and I am asking how to deserialize the class which has a self reference?

like image 969
Global Warrior Avatar asked Nov 26 '13 13:11

Global Warrior


3 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

like image 107
borjab Avatar answered Nov 14 '22 11:11

borjab


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

like image 29
ValerioMC Avatar answered Nov 14 '22 11:11

ValerioMC


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> {
like image 8
ericbn Avatar answered Nov 14 '22 09:11

ericbn