I've found oodles of resources on this, such as this one - Infinite Recursion with Jackson JSON and Hibernate JPA issue. I've tried to implement all of the various suggestions described there (including basic @JsonIgnore), but to no avail. I can't get anything other than infinite recursion errors regardless of what I try. I think I have a pretty similar/typical setup, but obviously with something wrong since despite using @JsonManagedReference, @JsonBackReferencere and @JsonIdentityInfo annotations, I keep getting the error.
My tables are "exchange" and "stock", with a manytoMany between them, and I've been testing by via ExchangeEndpoint. I've confirmed that if I completely remove "stock" from "exchange" entity, the service works fine, but for some reason, the json annotations do not seem to have any affect. Below is what I think is the solution based on the second (but more popular) answer in the aforementioned Infinite Recursion with Jackson JSON and Hibernate JPA issue.
Exchange.java
@Entity
@Table(name = "exchange", schema = "public")
@XmlRootElement
@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="@id")
public class Exchange implements java.io.Serializable {
...
@OneToMany(fetch = FetchType.LAZY, mappedBy = "exchange")
@JsonManagedReference
public Set<Stock> getStocks() {
return this.stocks;
}
...
Stock.java
@Entity
@Table(name = "stock", schema = "public")
@XmlRootElement
@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="@id")
public class Stock implements java.io.Serializable {
...
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "exchangeid", nullable = false)
@JsonBackReference
@JsonIgnore
public Exchange getExchange() {
return this.exchange;
}
...
ExchangeEndpoint.java
@Stateless
@Path("/exchanges")
public class ExchangeEndpoint {
@PersistenceContext(unitName = "postgresql-ss4")
private EntityManager em;
...
@GET
@Produces("application/json")
public List<Exchange> listAll(@QueryParam("start") Integer startPosition,
@QueryParam("max") Integer maxResult) {
TypedQuery<Exchange> findAllQuery = em
.createQuery(
"SELECT DISTINCT e "
+ "FROM Exchange e "
+ "LEFT JOIN FETCH e.stocks "
+ "ORDER BY e.exchangeid",
Exchange.class);
if (startPosition != null) {
findAllQuery.setFirstResult(startPosition);
}
if (maxResult != null) {
findAllQuery.setMaxResults(maxResult);
}
final List<Exchange> results = findAllQuery.getResultList();
return results;
}
edit:
some of the error output to be sure i'm not misinterpreting something;
15:35:16,406 ERROR [org.jboss.resteasy.resteasy_jaxrs.i18n] (http-/0.0.0.0:8080-1) RESTEASY000100: Failed executing GET /exchanges/: org.jboss.resteasy.spi.WriterException: org.codehaus.jackson.map.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: net.hb.forge2RestServices.model.Exchange["stocks"]->org.hibernate.collection.internal.PersistentSet[0]->net.hb.forge2RestServices.model.Stock["exchange"]->net.hb.forge2RestServices.model.Exchange["stocks"]->org.hibe ... ... Exchange["stocks"]->org.hibernate.collection.internal.PersistentSet[0]->net.hb.forge2RestServices.model.Stock["exchange"]->net.hb.forge2RestServices.model.Exchange["stocks"]) at org.jboss.resteasy.core.ServerResponse.writeTo(ServerResponse.java:262)
Please let me know what additional information I can provide to help explain my debacle. tiy.
The issue is you have reference to Stock
s and back from Stock
you have reference to Exchange
. Therefore JSON goes to stock, back to Exchange
and then for Exchange
it will generate to all Stock
s and so on.
To break the cycle it's best to put JsonIgnore
annotation to the field which references the parent object - ManyToOne - in this case it's Stock.exchange field (or the getter for that).
This kind of issues is much more easily avoided if you don't expose your JPA entities through REST.
You should consider using DTOs on REST side and mapping entities to DTOs and the reverse either by coding a mapper manually or by generating one using MapStruct.
As a bonus you'll avoid security issues.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With