user3233996
user3233996

Reputation: 31

JAX-RS JSON serialization loop with JPA entities

I am developing a typical Java EE 7 application on Glassfish 4.0, using Netbeans 7.4. I have a set of JPA entities with all kinds of relationships. As it is probably a well-known issue, I face a problem (most likely caused by a serialization loop) when I try to expose an entity with a bidirectional relationship with another one using a JAX-RS service.

I have searched a lot for the solution. Apparently, the most clean way of solving this is to use Jackson providers instead of Jersey built-in ones. However, it has not been a success for me. I may be doing something wrong in the middle, and any hint would be much appreciated.

First Entity:

@Entity
public class User implements Serializable {

    @Id
    private long id;

    ...

    @OneToMany(
        mappedBy = "owner",
        cascade = CascadeType.ALL
    )
    private List<Playlist> playlists;

    ...

}

Second Entity:

@Entity
public class Playlist {

    @Id
    @GeneratedValue
    private long id;

    ...

    @NotNull
    @ManyToOne
    private User owner;

    ...

}

JAX-RS Service:

@Path("/user")
@Stateless
public class UserResource {

    @Inject
    private UserService userService;

    @GET
    @Path("/{username}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response getUser(@PathParam("username") String username) {
        return Response.ok(userService.getUser(username)).build();
    }

}

I have downloaded and included latest Jackson binary (jackson-core-2.3.1.jar) in my classpath and I can actually see something related to jackson in Glassfish server log when I deploy my application. If the returned user entity does not have any associated playlists, everything is fine. However, with one or more playlists for the specified user, a HTTP 500 error is returned and nothing shows up in Glassfish server log.

Thanks in advance for any help.

UPDATE

After lots of back and forth. I am still unable to make jackson work. I moved to Wildfly (Jboss 8), and I cannot make it use the provided version of jackson instead of the built-in one. No matter which version of jackson is added in the classpath (with or without Maven), the error always indicates org.codehaus.jackson.*.

Upvotes: 3

Views: 3809

Answers (2)

Renato Probst
Renato Probst

Reputation: 6054

Find the @MGorgon answer useful.

In my case I want to use hibernate along with jersey but retrieve only id of relation (and not loading the entire object) in a RestFull json web service.

I end up creating a field for the id:

@JsonIgnoreProperties({"parent"}) // this ignores the object for json serialization
public class Object{
  private int id;
  private AnotherObj parent;
  @Transient // this ignores the properties for hibernate mapping, cause we want to use the parent.getId() instead. You may have to put it in your get too
  private ind parent_id;
}

Then in your ObjectDao query you can define the parent id as parent_id if you need to get it from a relation :

something like "from files WHERE user_id = parent_id").

You will have to do this for all your queries:

  Object.setParent_id(Object.getParent().getId());

Because parent_id is transient, invisible to hibernate and it wont be listed otherwise.

And of course you should use LAZY relations (otherwise it would load the obj anyway). It works because the parent_id is a column of the object table, it wont need to make a call to parent.

This is useful when you have a lot of relations but you just need to query the id.

Upvotes: 1

MGorgon
MGorgon

Reputation: 2607

Modify your Playlist entity class:

@Entity
@JsonIgnoreProperties({"owner"})
public class Playlist {

Your Jackson is running to recurency when he tries to serialize User which have Playlist which have User and so on...

Upvotes: 1

Related Questions