关于java:带JPA实体的JAX-RS JSON序列化循环

JAX-RS JSON serialization loop with JPA entities

我正在使用NETBeaS 7.4开发GelasFISH 4上的典型JavaEE 7应用程序。我有一组具有各种关系的JPA实体。因为这可能是一个众所周知的问题,所以当我试图使用JAX-RS服务公开与另一个实体具有双向关系的实体时,我面临一个问题(很可能是由序列化循环引起的)。

我一直在寻找解决方案。显然,解决这一问题的最干净的方法是使用Jackson提供商,而不是Jersey内置提供商。然而,这对我来说并不成功。我可能在中间做了一些错误的事情,任何暗示都会很感激。

第一实体:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Entity
public class User implements Serializable {

    @Id
    private long id;

    ...

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

    ...

}

第二实体:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Entity
public class Playlist {

    @Id
    @GeneratedValue
    private long id;

    ...

    @NotNull
    @ManyToOne
    private User owner;

    ...

}

JAX-RS服务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@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();
    }

}

我在类路径中下载并包含了最新的杰克逊二进制文件(jackson-core-2.3.1.jar),在部署应用程序时,我可以在Glassfish服务器日志中看到与杰克逊相关的内容。如果返回的用户实体没有任何关联的播放列表,则一切正常。但是,对于指定用户的一个或多个播放列表,将返回HTTP 500错误,并且Glassfish服务器日志中不会显示任何内容。

事先谢谢你的帮助。

更新

在多次来回之后。我还是不能让杰克逊工作。我搬到了Wildfly(JBoss8),我不能让它使用提供的杰克逊版本而不是内置版本。无论在类路径中添加了哪个版本的Jackson(有或没有Maven),错误始终指示org.codehaus.jackson.*。


找到@mgorgon答案很有用。

在我的例子中,我希望将Hibernate与Jersey一起使用,但只在restfull JSON Web服务中检索关系ID(而不是加载整个对象)。

最后我为ID创建了一个字段:

1
2
3
4
5
6
7
@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;
}

然后,在ObjectDAO查询中,如果需要从关系中获取父ID,可以将父ID定义为父ID:

类似于"从用户u id=父u id")的文件。

对于您的所有查询,您必须执行此操作:

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

因为parent_id是暂时的,对冬眠是不可见的,所以它不会被列出。

当然,你应该使用懒惰的关系(否则它会加载obj)。它工作是因为父对象表的列是父对象表的列,所以不需要调用父对象表。

当您有很多关系,但只需要查询ID时,这很有用。


修改您的Playlist实体类:

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

当你的杰克逊试图序列化有用户的播放列表的用户时,他正在运行到递归…