Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Json, JPA, ManytoOne and OneToMany => recursive

I've tried to read all the Qs about this topic and still there is something I'm missing.

My problem is: that the two tables KIDS and PARENT are calling eachother recursivly

I've got an EJB asking for a Parent with an id, - I've (I think) used @OneToMany(mappedBy="parent") where needed. The result could be better: When asking for the parent (with an id) it that sees there is a kid that take the parent that ask for the kid... (in an almost never ending story :)

JSON OUTPUT

{
  "parentsid": 1,
  ...
  "parentsusername": null,
  "calendars": [],
  "kids": [
    {
      "kidsid": 2,
        ...
      "parent": {
        "parentsid": 1,
        ...
        "calendars": [],
        "kids": [
          {
            "kidsid": 2,               
            "calendars": [],
            "checkins": [],
            "parent": {
              "parentsid": 1,                 
              "calendars": [],
              "kids": [
                {
                  "kidsid": 2,                     
                  "calendars": [],    
                 .....

The Classes I've got a Stateless Bean calling:

@Stateless
@LocalBean
@Path("/checkin")
public class CheckinService {

 @PersistenceContext(unitName="chkin",type=PersistenceContextType.TRANSACTION)
 EntityManager entityManager;

@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/{id}")    
public Parent read(@PathParam("id") int id) {
    Parent parent = entityManager.find(Parent.class, id);        
    return parent;
}

The Entity classes are made the following way with

/**
 * The persistent class for the KIDS database table.
 */
@Entity
@Table(name="KIDS")
@NamedQuery(name="Kid.findAll", query="SELECT k FROM Kid k")
public class Kid implements Serializable {
    private static final long serialVersionUID = 1L;

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

    //bi-directional many-to-one association to Calendar
    @OneToMany(mappedBy="kid")
    private List<Calendar> calendars;

    //bi-directional many-to-one association to Checkin
    @OneToMany(mappedBy="kid")
    private List<Checkin> checkins;

    //bi-directional many-to-one association to Parent
    @ManyToOne             **// <=============**
    @JoinColumn(name="parentsId")
    private Parent parent;
}

Entity call for Parents:

@Entity
@Table(name="PARENTS")
@NamedQuery(name="Parent.findAll", query="SELECT p FROM Parent p")
public class Parent implements Serializable {
    private static final long serialVersionUID = 1L;

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

    ...

    //bi-directional many-to-one association to Calendar
    @OneToMany(mappedBy="parent")
    private List<Calendar> calendars;

    //bi-directional many-to-one association to Kid
    @OneToMany(mappedBy="parent") **// <=============**
    private List<Kid> kids;

The Database look like this: Two database Tables one named PARENTS and one KIDS there is a onetomany from PARENTS to KIDS with a foreng key called FK-KIDS_parentsID

PARENTS ==========FK_KIDS_parentsId==========< KIDS
(PK) PARENTSID                                 (PK) KIDSID
                                               (FK) parentsId

Stacktrace

[error occurred during error reporting (printing native stack), id 0xc0000005]

Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j  sun.nio.ch.WindowsSelectorImpl$SubSelector.poll0(JI[I[I[IJ)I+0
j  sun.nio.ch.WindowsSelectorImpl$SubSelector.poll()I+43
j  sun.nio.ch.WindowsSelectorImpl$SubSelector.access$400(Lsun/nio/ch/WindowsSelectorImpl$SubSelector;)I+1
j  sun.nio.ch.WindowsSelectorImpl.doSelect(J)I+63
j  sun.nio.ch.SelectorImpl.lockAndDoSelect(J)I+37
j  sun.nio.ch.SelectorImpl.select(J)I+30
j  sun.nio.ch.SelectorImpl.select()I+2
j  org.xnio.nio.SelectorUtils.await(Lorg/xnio/nio/NioXnio;Ljava/nio/channels/SelectableChannel;I)V+23
j  org.xnio.nio.NioSocketConduit.awaitWritable()V+26
j  org.xnio.conduits.AbstractSinkConduit.awaitWritable()V+7
j  io.undertow.conduits.ChunkedStreamSinkConduit.awaitWritable()V+7
j  org.xnio.conduits.ConduitStreamSinkChannel.awaitWritable()V+4
j  io.undertow.channels.DetachableStreamSinkChannel.awaitWritable()V+20
j  io.undertow.server.HttpServerExchange$WriteDispatchChannel.awaitWritable()V+20
j  org.xnio.channels.Channels.writeBlocking(Ljava/nio/channels/GatheringByteChannel;[Ljava/nio/ByteBuffer;II)J+34
j  io.undertow.servlet.spec.ServletOutputStreamImpl.write([BII)V+311
j  org.jboss.resteasy.plugins.server.servlet.HttpServletResponseWrapper$DeferredOutputStream.write([BII)V+15
j  org.jboss.resteasy.util.CommitHeaderOutputStream.write([BII)V+11
j  com.fasterxml.jackson.core.json.UTF8JsonGenerator._flushBuffer()V+24
j  com.fasterxml.jackson.core.json.UTF8JsonGenerator._writeBytes([B)V+17
J 1041 C2 com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(Ljava/lang/Object;Lcom/fasterxml/jackson/core/JsonGenerator;Lcom/fasterxml/jackson/databind/SerializerProvider;)V (185 bytes) @ 0x0000000002979c78 [0x00000000029796c0+0x5b8]
j  com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(Ljava/lang/Object;Lcom/fasterxml/jackson/core/JsonGenerator;Lcom/fasterxml/jackson/databind/SerializerProvider;)V+41
J 1041 C2 com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(Ljava/lang/Object;Lcom/fasterxml/jackson/core/JsonGenerator;Lcom/fasterxml/jackson/databind/SerializerProvider;)V (185 bytes) @ 0x0000000002979b78 [0x00000000029796c0+0x4b8]
j  com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(Ljava/lang/Object;Lcom/fasterxml/jackson/core/JsonGenerator;Lcom/fasterxml/jackson/databind/SerializerProvider;)V+41
j  com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(Ljava/util/List;Lcom/fasterxml/jackson/core/JsonGenerator;Lcom/fasterxml/jackson/databind/SerializerProvider;)V+163
j  com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(Ljava/lang/Object;Lcom/fasterxml/jackson/core/JsonGenerator;Lcom/fasterxml/jackson/databind/SerializerProvider;)V+7
j  com.fasterxml.jackson.databind.ser.std.AsArraySerializerBase.serialize(Ljava/lang/Object;Lcom/fasterxml/jackson/core/JsonGenerator;Lcom/fasterxml/jackson/databind/SerializerProvider;)V+34
J 1041 C2 com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(Ljava/lang/Object;Lcom/fasterxml/jackson/core/JsonGenerator;Lcom/fasterxml/jackson/databind/SerializerProvider;)V (185 bytes) @ 0x0000000002979b78 [0x00000000029796c0+0x4b8]
j  com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(Ljava/lang/Object;Lcom/fasterxml/jackson/core/JsonGenerator;Lcom/fasterxml/jackson/databind/SerializerProvider;)V+41
J 1041 C2 com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(Ljava/lang/Object;Lcom/fasterxml/jackson/core/JsonGenerator;Lcom/fasterxml/jackson/databind/SerializerProvider;)V (185 bytes) @ 0x0000000002979b78 [0x00000000029796c0+0x4b8]
j  com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(Ljava/lang/Object;Lcom/fasterxml/jackson/core/JsonGenerator;Lcom/fasterxml/jackson/databind/SerializerProvider;)V+41
j  com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(Ljava/util/List;Lcom/fasterxml/jackson/core/JsonGenerator;Lcom/fasterxml/jackson/databind/SerializerProvider;)V+163
j  com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(Ljava/lang/Object;Lcom/fasterxml/jackson/core/JsonGenerator;Lcom/fasterxml/jackson/databind/SerializerProvider;)V+7
j  com.fasterxml.jackson.databind.ser.std.AsArraySerializerBase.serialize(Ljava/lang/Object;Lcom/fasterxml/jackson/core/JsonGenerator;Lcom/fasterxml/jackson/databind/SerializerProvider;)V+34
J 1041 C2 com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(Ljava/lang/Object;Lcom/fasterxml/jackson/core/JsonGenerator;Lcom/fasterxml/jackson/databind/SerializerProvider;)V (185 bytes) @ 0x0000000002979b78 [0x00000000029796c0+0x4b8]
j  com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(Ljava/lang/Object;Lcom/fasterxml/jackson/core/JsonGenerator;Lcom/fasterxml/jackson/databind/SerializerProvider;)V+41
J 1041 C2 com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(Ljava/lang/Object;Lcom/fasterxml/jackson/core/JsonGenerator;Lcom/fasterxml/jackson/databind/SerializerProvider;)V (185 bytes) @ 0x0000000002979b78 [0x00000000029796c0+0x4b8]
j  com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(Ljava/lang/Object;Lcom/fasterxml/jackson/core/JsonGenerator;Lcom/fasterxml/jackson/databind/SerializerProvider;)V+41
like image 780
Henrik Avatar asked Sep 20 '25 10:09

Henrik


2 Answers

As the comments indicate, this doesn't seem to be so much a JPA issue as it is a JSON serialization issue. Fortunately, Jackson provides several annotations to deal with this sort of situation.

Use @JsonManagedReference on the parent and @JsonBackReference on the child, and you may want to try playing with @JsonIdentityInfo.

Here's some more reading you may find helpful.

like image 168
dcsohl Avatar answered Sep 23 '25 01:09

dcsohl


This is a problem with Circular dependencies and JSON serialization, an easy way to solve this would be to use @JsonIdentityInfo on both classes, you should have something like this:

@Entity
@Table(name="KIDS")
@NamedQuery(name="Kid.findAll", query="SELECT k FROM Kid k")
@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id")
public class Kid implements Serializable {

and

@Entity
@Table(name="PARENTS")
@NamedQuery(name="Parent.findAll", query="SELECT p FROM Parent p")
@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id")
public class Parent implements Serializable {

This way you ensure that in each kid serialization the parent won't be serialized but you'll get only his id instead.

like image 23
saadel Avatar answered Sep 22 '25 23:09

saadel