【问题标题】:Hibernate and TomEE+ bidirectional association causes json recursivenessHibernate和TomEE+双向关联导致json递归
【发布时间】:2018-12-17 00:32:08
【问题描述】:

我将 TomEE 9.0.12 与 Hibernate 5.3.7 一起使用,由于 json 递归性,我目前遇到了 stackoverflow 异常。请注意,我没有使用 jackson,理想情况下也不想使用,而是使用 TomEE+ 附带的标准:org.apache.johnzon。

例外情况:

Caused by: java.lang.StackOverflowError
    at org.apache.johnzon.mapper.Mappings.findOrCreateClassMapping(Mappings.java:340)
    at org.apache.johnzon.mapper.MappingGeneratorImpl.doWriteObjectBody(MappingGeneratorImpl.java:240)

这是我的 User.java 类:

import javax.persistence.*;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

/**
 * A user
 */
@Entity
@Table(name = "users")
public class User implements Serializable {

    private static final long serialVersionUID = -9012412584251217L;

    // TODO: 16/12/2018 they keep nesting each other: { user { posts { user { posts } } }  }

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @Column(name = "username")
    private String username;

    @Column(name = "email")
    private String email;

    @Column(name = "password")
    private String password;

    @Column(name = "salt")
    private String salt;

    @OneToMany(mappedBy = "user")
    private Set<Post> posts = new HashSet<>();

    /**
     * Constructs an empty user (for persistence purposes)
     */
    public User() {}

    // Setters and getters removed for convenience
}

这是我的 Post.java

import javax.persistence.*;
import java.io.Serializable;

/**
 * Project created by ExpDev
 */
@Entity
@Table(name = "posts")
public class Post implements Serializable {

    private static final long serialVersionUID = -9887234238952234L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @ManyToOne
    @JoinColumn(name = "user_id")
    private User user;

    @Column(name = "data")
    private String data;

    /**
     * Constructs an empty post (for persistence purposes)
     */
    public Post() {}

    // Setters and getters removed for convenience
}

问题

问题是他们会不断地互相引用。用户会引用帖子,而用户又会引用用户,而用户又会引用帖子——于是邪恶的循环继续下去。

我知道我可以在 User.java 中的“用户”上使用 org.apache.johnzon 的注释 @JsonbTransient 使其不序列化它,但这使得它永远不会显示(我想要,但有条件)。我为什么要这样?

因为,假设 GET /users/1 被访问,1 是用户的 id,我想显示所有用户的帖子(或至少是他们的 ID),但不希望它返回给用户(用户内的帖子内的嵌套用户)。

但是,如果 GET /api/posts/3, 3 是 id,我希望它显示发布帖子的用户,而不是用户内部的帖子。

所以基本上,注释必须在某种程度上是有条件的,并且是具体的。目前,这就是我检索和显示用户的方式(访问该方法时,框架会自动将返回的对象转换为 JSON)。

@GET
@Path("/{id}")
public User get(@PathParam("id") Long id) {
    // Find the user and return them
    return HiberUtil.getSession().get(User.class, id);
}

提前感谢您!我已经搜索了 5 个小时,但没有解决方案或阅读材料能够解决我的问题。

【问题讨论】:

    标签: java json hibernate stack-overflow apache-tomee


    【解决方案1】:

    我通过从 TomEE+ 迁移到 Spring Framework(带有嵌入式 Tomcat 服务器)解决了这个问题,它默认使用 Jackson 而不是“org.apache.johnzon”。有了这个,我能够使用有用的注释:

    @JsonIdentityInfo(
      generator = ObjectIdGenerators.PropertyGenerator.class,
      property = "id")
    @JsonIdentityReference(alwaysAsId=true)
    private List<Post> posts;
    

    这样做是为了让 JSON 看起来像这样:

    {
        "username":"test",
        "posts": [2, 5, 6, 8, 2]
    }
    

    对于 Post 中的 User 也是如此,当然它也标有这些注释。这正是我想要的,以及我使用的前端 Web 框架、EmberJS 和许多类似框架如何期望返回数据。所以这对我来说是完美的。此外,在使用嵌入式 Tomcat 服务器使用 Spring 一段时间后,我也更喜欢它(我也使用过 Glassfish,但不喜欢它)。

    重要的是要注意,修复不是因为我搬到了 Spring,而是因为我使用了 Jackson。如果您仍想使用 TomEE+,可以,请参阅https://stackoverflow.com/a/38915278/7120095,了解如何在 TomEE 中使用 jackson 而不是 johnzon。

    【讨论】:

      【解决方案2】:

      作为参考,johnzon 支持通过映射器上的 deduplicateObjects 选项(tomee 7)和 johnzon.deduplicateObjects 属性(tomee 8、meecrowave 等)处理引用。这解决了用 jsonpointer 替换已经看到的引用的问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-07-26
        • 2018-09-23
        • 1970-01-01
        • 2016-05-16
        • 2011-07-18
        • 1970-01-01
        相关资源
        最近更新 更多