3

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.*.

user3233996
  • 31
  • 1
  • 4

2 Answers2

1

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...

MGorgon
  • 2,547
  • 23
  • 41
  • It doesn't work. If there is a suspicion that jackson is not active or is not able to read this annotation, I don't know actually how to make sure. Anyway, it would not be a good solution simply because I may want to expose a playlist through a RESTful service, and it that case, I certainly want the owner to be serialized too. – user3233996 Jan 25 '14 at 01:58
  • http://stackoverflow.com/questions/13630096/cyclic-references-in-a-bidirectional-many-to-many-relationship – MGorgon Jan 25 '14 at 02:03
  • http://stackoverflow.com/questions/3340485/how-to-solve-circular-reference-in-json-serializer-caused-by-hibernate-bidirecti – MGorgon Jan 25 '14 at 02:03
  • http://stackoverflow.com/questions/10097865/jackson-confused-with-bidirectional-one-to-many-relationship – MGorgon Jan 25 '14 at 02:03
  • http://jackson-users.ning.com/forum/topics/deserializing-objects-with-bi-directional-many-to-many-relations – MGorgon Jan 25 '14 at 02:04
  • http://ankeetmaini.wordpress.com/2012/07/26/json-troubleshooting-circular-dependency-errors/ – MGorgon Jan 25 '14 at 02:05
  • http://forum.spring.io/forum/spring-projects/web/81228-infinite-recursion-with-jackson-json-and-jpa – MGorgon Jan 25 '14 at 02:05
  • @user3233996 You said you downloaded `jackson-core-2.3.1.jar`, you should also download `jackson-annotations-2.3.1` to use `@JsonIgnore*` annotations. The import should be something like `com.fasterxml.jackson.annotation.JsonIgnore`, not `org.codehaus.jackson.JsonIgnore`. – rubenlop88 Jan 25 '14 at 05:17
1

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.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Renato Probst
  • 5,914
  • 2
  • 42
  • 45