【问题标题】:Many to many Infinite recursion using Jackson and Hibernate使用 Jackson 和 Hibernate 进行多对多无限递归
【发布时间】:2015-12-16 05:20:34
【问题描述】:

由于多对多关系的循环引用而出现以下错误。

org.codehaus.jackson.map.JsonMappingException: Infinite recursion (StackOverflowError)

我尝试过使用 @JsonIdentityInfo@com.fasterxml.jackson.annotation.JsonIgnore@JsonManagedReference,但这些都不适合我。我正在使用 lombok,因此使用了 @getter/setter。

用户表

@Entity
@Table(name = "user")
@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="user_id", scope=User.class)
public class User implements Serializable{

    @Getter
    @Setter
    @Id
    @GeneratedValue(strategy = IDENTITY, generator = "increment")
    @GenericGenerator(name = "increment", strategy = "increment")
    public int user_id;

    @JsonManagedReference
    @Getter
    @Setter
    @com.fasterxml.jackson.annotation.JsonIgnore
    @ElementCollection(targetClass=UserInterest.class)
    @OneToMany(fetch = FetchType.EAGER, mappedBy = "pk.user", cascade=CascadeType.ALL)
    public Set<UserInterest> userInterestSet = new HashSet<UserInterest>();
}

利息表

@Entity
@Table(name = "interest")
@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="interest_id", scope=Interest.class)
public class Interest implements Serializable{

    @Getter
    @Setter
    @Id
    @GeneratedValue(strategy = IDENTITY, generator = "increment")
    @GenericGenerator(name = "increment", strategy = "increment")
    public int interest_id;

    @Getter
    @Setter
    @Column(name = "interest_name", nullable = false, length=100)
    public String interest_name;

    @Getter
    @Setter
    @com.fasterxml.jackson.annotation.JsonIgnore
    @OneToMany(fetch = FetchType.EAGER, mappedBy = "pk.interest", cascade=CascadeType.ALL)
    public Set<UserInterest> userInterestSet = new HashSet<UserInterest>();
}

UserInterest 连接表

@Entity
@Table(name="user_interest")
@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="pk", scope=UserInterest.class)
@AssociationOverrides({
        @AssociationOverride(name="pk.user", joinColumns=@JoinColumn(name="user_id")),
        @AssociationOverride(name="pk.interest", joinColumns=@JoinColumn(name="interest_id"))
})
public class UserInterest implements Serializable {
    @Getter
    @Setter
    @com.fasterxml.jackson.annotation.JsonIgnore
    @GeneratedValue(generator = "increment")
    @GenericGenerator(name = "increment", strategy = "increment")
    public int user_interest_id;

    @EmbeddedId
    @Getter
    @Setter
    @com.fasterxml.jackson.annotation.JsonIgnore
    public UserInterestId pk;

    @Transient
    @Getter
    @Setter
    @com.fasterxml.jackson.annotation.JsonIgnore
    public User user;

    @Transient
    @Getter
    @Setter
    @com.fasterxml.jackson.annotation.JsonIgnore
    public Interest interest;
}

UserInterestId 类

@Embeddable
@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id", scope=UserInterestId.class)
public class UserInterestId implements Serializable{
    @Getter
    @Setter
    @org.codehaus.jackson.annotate.JsonIgnore

    @ManyToOne(fetch = FetchType.LAZY)
    @com.fasterxml.jackson.annotation.JsonIgnore
    @JsonBackReference
    public User user;

    @Getter
    @Setter
    @JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="interest_id")
    @ManyToOne(fetch = FetchType.LAZY)
    @com.fasterxml.jackson.annotation.JsonIgnore
    @JsonBackReference
    public Interest interest;
}

当我在加入的用户对象上运行以下命令时,我得到了错误:

ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
ow.writeValueAsString(userSet);

我对 Hibernate 还是很陌生,所以希望得到任何指点。我已经阅读了 5-10 篇建议我上面提到的解决方案的 SO 文章,但我仍然无法停止循环引用。非常感谢!

【问题讨论】:

    标签: java mysql json hibernate recursion


    【解决方案1】:

    您应该取消代理您的对象。来自here的示例

    @SuppressWarnings("unchecked")
    protected T unproxy(T entity){
        if (entity == null) {
            return null;
        }
    
        if (entity instanceof HibernateProxy) {
            try {
                Hibernate.initialize(entity);
            } catch (ObjectNotFoundException e) {
                return null;
            }
            entity = (T) ((HibernateProxy) entity).getHibernateLazyInitializer().getImplementation();
        }
        return entity;
    }
    

    或者这样(来自here

    public <P> List<P> unproxy(Collection<P> objects) {
        Session session = sessionFactory.getCurrentSession();
        List<P> result = new ArrayList<P>();
        for (P t : objects) {
            Object unproxied = ((SessionImplementor)session).getPersistenceContext().unproxy(t);
            result.add((P) unproxied);
        }
        return result;
    }
    

    【讨论】:

    • 嗯。谢谢。第一种方法不起作用,因为它不是 HibernateProxy 的实例。第二个执行正常,但不更改对象。它仍然会导致无限循环。
    • 你将什么传递给方法?
    • 第二个,基本上是这样的:session = sessionFactory.openSession().beginTransaction() .... session.createQuery(hql) **。 ... **users = unproxy(users, session); // 我添加了 session 作为代替 sessionFactory.getCurrentSession() 的参数。
    • 它似乎从来都不是 HibernateProxy 的实例。我也将它切换到 FetchType.LAZY 但仍然没有 HibernateProxy 的实例。
    • 用户列表不是代理对象。您需要取消代理列表中的每个用户实例
    【解决方案2】:

    找到了解决办法。对于我的 ObjectWriter/ObjectMapper,我切换到 com.fasterxml.jackson.databind.ObjectWriter / Mapper 而不是 codehaus。似乎 jsonIgnore 和 JsonIdentityInfo 只是没有被 codehaus.jackson.map 承认,或者至少没有被我的版本承认。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-02
      • 2014-05-16
      • 2021-11-15
      • 1970-01-01
      • 2020-07-25
      相关资源
      最近更新 更多