31

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?

Shawn J. Molloy
  • 2,457
  • 5
  • 41
  • 59
Global Warrior
  • 5,050
  • 9
  • 45
  • 75

6 Answers6

18

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

lrkwz
  • 6,105
  • 3
  • 36
  • 59
borjab
  • 11,149
  • 6
  • 71
  • 98
13

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

ValerioMC
  • 2,926
  • 13
  • 24
8

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> {
ericbn
  • 10,163
  • 3
  • 47
  • 55
3

Try @JsonIdentityInfo annotation as given in this example. More details here http://wiki.fasterxml.com/JacksonFeatureObjectIdentity

@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="@id")
public class Identifiable
{
    public int value;

    public Identifiable next;
}
MFIhsan
  • 1,037
  • 3
  • 15
  • 35
1

Please refer to related question and a sensible way of handling this in my opinion. https://stackoverflow.com/a/65920426/12594701

In current case it would help to annotate 'previous' like below

@JsonIgnoreProperties({"previous"})//... along with other annotations
private T previous;
RM_SNSS
  • 21
  • 3
-8

I guess somewhere in your code. The previous of some instance of DailyActivity point to itself.

  • Ya, it obviously does. Let me re-frame the question how can you deserialize an object which has a self reference? – Global Warrior Nov 26 '13 at 13:49
  • I don't think you can. I will set the previous to null when it points to itself before send the object. In other end, after recevied the object, change the previous to itself if it's null. Maybe someone else have better idea. – Yiheng Wang Nov 26 '13 at 14:03