4

I am using JPA EclipseLink to model a one to many relationship between UseCase and PainPoint. I am able to insert the values fine. Thereafter, I am using JAX-RS to retrieve the data using a GET method. The GET method fails with the error - Generating incomplete JSON.

Console Log:

  • [EL Fine]: INSERT INTO USECASE (UseCaseID, Description) VALUES (?, ?) bind => [1, Description]
  • [EL Fine]: INSERT INTO PAIN_POINT (PainPointID, PainPointDescription, USECASE_ID) VALUES (?, ?, ?) bind => [2, Pain Point 1, 1]
  • [EL Fine]: SELECT UseCaseID, Description FROM USECASE
  • Nov 17, 2017 7:16:22 PM org.eclipse.yasson.internal.Marshaller marshall SEVERE: Generating incomplete JSON

UseCase:

@NamedQueries({@NamedQuery(name = "getAllUseCases", query = "SELECT c FROM UseCase c")})

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@NotNull
@Column(name = "UseCaseID")
private int UseCaseID;

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

@OneToMany(mappedBy="usecase", cascade=CascadeType.ALL, fetch=FetchType.EAGER)
private Collection<PainPoint> painPoints = new ArrayList<PainPoint>();

PainPoint:

@NamedQueries({@NamedQuery(name = "getAllPainPoints", query = "SELECT c FROM PainPoint c")})

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@NotNull
@Column(name = "PainPointID")
private int PainPointID;

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

@ManyToOne
@JoinColumn (name="USECASE_ID", referencedColumnName="UseCaseID")
private UseCase usecase;

DataLoader:

UseCase useCase = new UseCase("Description 1");
PainPoint painPoint1 = new PainPoint("Pain Point 1", useCase);
useCase.getPainPoints().add(painPoint1);
em.persist(useCase);

UseCaseService:

@GET
@Path("/")
public List<UseCase> getUseCases() {

List<UseCase> retVal = null;

EntityManagerFactory emf = Utility.getEntityManagerFactory();
EntityManager em = emf.createEntityManager();

retVal = em.createNamedQuery("getAllUseCases").getResultList();

return retVal;
}
  • and clearly JSON generation is nothing to do with the JPA API, so why not debug down to where your JSON is generated, using what code ... –  Nov 18 '17 at 13:53
  • I guess I should have included this info in the original post. But it seems like there is some kind of cyclic recursive search going on. For example, UseCase has PainPoints. And PainPoint is tied to a UseCase. So the JSON runs into errors... Not sure how to get around it in One to Many relationships. – Milton Chandradas Nov 18 '17 at 16:37
  • 1
    I removed the getters and setters on the PainPoint object that references UseCase and now it seems to work. Lol. Should have guessed it. Hopefully, I don't run into other issues. – Milton Chandradas Nov 18 '17 at 16:45

3 Answers3

9

Add the annotation @JsonbTransient (package: javax.json.bind.annotation.JsonbTransient) on the getter methods for cyclic references, or any other derived fields. This is equivalent to the @XmlTranisent annotation for XML generation and will prevent the conversion to JSON entering an infinite loop.

Depends on your toolset I guess, but for me using NetBeans, when the entity class is generated automatically the annotation for XML is added but not for JSON. Just match each @XmlTransient with an equivalent @JsonbTransient

Dale
  • 3,193
  • 24
  • 29
2

According to what Dale said above. You can add the following Maven dependency

<dependency>
    <groupId>javax.json.bind</groupId>
    <artifactId>javax.json.bind-api</artifactId>
    <version>1.0</version>
</dependency>

More information about @JsonbTransient can be found in the link

Sheila Mbadi
  • 116
  • 5
2

This is most probably caused by Circular Reference, There are two ways handling this issue as described on Json and Java - Circular Reference:

  1. @JsonIgnore
  2. @JsonManagedReference and @JsonBackReference

I suggest you take the second approach and add these two annotation two avoid circular reference issue as :

@OneToMany(mappedBy="usecase", cascade=CascadeType.ALL, fetch=FetchType.EAGER)
@JsonBackReference                ///// ADD THIS ANNOTATION
private Collection<PainPoint> painPoints = new ArrayList<PainPoint>();


@ManyToOne
@JoinColumn (name="USECASE_ID", referencedColumnName="UseCaseID")
@JsonManagedReference              ///// ADD THIS ANNOTATION
private UseCase usecase;

More Info: