JPA多人与日食&;GSON循环引用导致服务器重新启动后堆栈溢出
我有一个问题与许多双向JPA映射,这是造成我的堆栈溢出错误 虽然我的应用程序中总共有5个实体,但我相信这个问题只与其中的2个有关,为了简单起见,下面将对其中的2个进行描述 实体: 应用 使用者 一个应用程序可以有许多开发人员 用户可以开发许多应用程序 以下是它们的映射方式: //应用实体:JPA多人与日食&;GSON循环引用导致服务器重新启动后堆栈溢出,jpa,reference,gson,many-to-many,circular-reference,Jpa,Reference,Gson,Many To Many,Circular Reference,我有一个问题与许多双向JPA映射,这是造成我的堆栈溢出错误 虽然我的应用程序中总共有5个实体,但我相信这个问题只与其中的2个有关,为了简单起见,下面将对其中的2个进行描述 实体: 应用 使用者 一个应用程序可以有许多开发人员 用户可以开发许多应用程序 以下是它们的映射方式: //应用实体: @ManyToMany private List<Users> users 用户 身份证件 一, 现在,当服务器停止并重新启动时,或者当应用程序使用createtables重新部署时 (vs d
@ManyToMany
private List<Users> users
用户身份证件 一, 现在,当服务器停止并重新启动时,或者当应用程序使用createtables重新部署时 (vs drop和create tables)(数据存在于表中)然后我在每个entities toString()函数中得到一个堆栈溢出。 我在debug中使用断点在Applications toString()函数和Users toString()函数上运行了这个函数,我可以单击resume并观察每个toString()函数被反复调用,直到 导致堆栈溢出 以下是控制台日志: (正在执行实体查询) 【EL Fine】:2014-01-21 14:48:44.383--服务器会话(1615948530)--连接(49767657)--线程(线程[http-bio-8080-exec-9,5,main])--选择 t1.ID,t1.APPIDENTIFIER,t1.DATECREATED,t1.DATEMODIFIED, t1.DEVICETYPE来自应用程序\用户t0,应用程序t1,其中 ((t0.users\u ID=?)和(t1.ID=t0.applications\u ID)) (调用第二个实体查询) 【EL Fine】:2014-01-21 14:50:02.444--服务器会话(1615948530)--连接(1871047709)--线程(线程[http-bio-8080-exec-9,5,main])--选择 t1.ID,t1.DATECREATED,t1.DATEMODIFIED,t1.EMAIL,t1.FIRSTNAME, t1.FULLNAME,t1.lastloginandate,t1.LASTNAME,t1.USERNAME FROM 应用程序用户t0、用户t1,其中((t0.APPLICATIONS\U ID=?)和 (t1.ID=t0.users\u ID)) [EL Finest]:2014-01-21 14:50:02.471——服务器会话(1615948530)——连接(1601422824)——线程(线程[http-bio-8080-exec-9,5,main])——连接 已释放到连接池[读取] java.lang.StackOverflower错误
at java.util.Vector.get(Vector.java:693)
at java.util.AbstractList$Itr.next(AbstractList.java:345)
at java.util.AbstractCollection.toString(AbstractCollection.java:421)
at java.util.Vector.toString(Vector.java:940)
at org.eclipse.persistence.indirection.IndirectList.toString(IndirectList.java:797)
at java.lang.String.valueOf(String.java:2826)
at java.lang.StringBuilder.append(StringBuilder.java:115)
at com.sap.crashlogserver.dao.entities.Applications.toString(Applications.java:150)
at java.lang.String.valueOf(String.java:2826)
at java.lang.StringBuilder.append(StringBuilder.java:115)
at java.util.AbstractCollection.toString(AbstractCollection.java:422)
at java.util.Vector.toString(Vector.java:940)
at org.eclipse.persistence.indirection.IndirectList.toString(IndirectList.java:797)
at java.lang.String.valueOf(String.java:2826)
at java.lang.StringBuilder.append(StringBuilder.java:115)
at com.sap.crashlogserver.dao.entities.Users.toString(Users.java:168)
at java.lang.String.valueOf(String.java:2826)
at java.lang.StringBuilder.append(StringBuilder.java:115)
at java.util.AbstractCollection.toString(AbstractCollection.java:422)
at java.util.Vector.toString(Vector.java:940)
at org.eclipse.persistence.indirection.IndirectList.toString(IndirectList.java:797)
at java.lang.String.valueOf(String.java:2826)
at java.lang.StringBuilder.append(StringBuilder.java:115)
at com.sap.crashlogserver.dao.entities.Applications.toString(Applications.java:150)
at java.lang.String.valueOf(String.java:2826)
at java.lang.StringBuilder.append(StringBuilder.java:115)
at java.util.AbstractCollection.toString(AbstractCollection.java:422)
at java.util.Vector.toString(Vector.java:940)
根据我读到的大量线程,我尝试:
1.颠倒映射,
2.将@JsonIgnore添加到某些实体字段
3.使用fetch=FetchType.LAZY
还有许多其他的配置调整,但都没有解决这个问题。
一些建议像使用瞬态场。我不确定我的JPA eclipselink实现是否支持这一点
我还阅读了一篇帖子,建议我实施gson.ExclusionStrategy。
我还没有试过这个
这就是故事。我是Java和JPA的新手。
这对我来说是一个很难解决的问题。
如果您有任何建议可以帮助我解决此问题,我们将不胜感激。您的objects-toString方法正在对整个模型递归调用toString。堆栈没有显示最初调用它的原因,但可能是由于某些日志记录设置。修复您的toString方法并关闭日志记录,也许这会对某人有所帮助 我也有同样的问题。我使用注释
@InvisibleJson
和自定义排除策略来隐藏这些字段
public class SafeDataExclusionStrategy implements ExclusionStrategy {
@Override
public boolean shouldSkipClass(Class<?> c) {
return false;
}
@Override
public boolean shouldSkipField(FieldAttributes c) {
return c.getAnnotation(InvisibleJson.class) != null;
}
}
像
@InvisibleJson
@许多(mappedBy=“角色”)
公开名单工作人员;
所以GSON不会在staff对象内部挖掘。非常简单的解决方案,在所有希望GSON序列化/反序列化的变量和列表上使用注释@Expose
一个基本上只允许GSON使用名称的简单示例:
@Expose
private String name;
@ManyToMany
private List<Users> users
@Expose
私有字符串名称;
@许多
私有列表用户
然后,在使用GsonBuilder的地方,执行以下操作:
GsonBuilder builder = new GsonBuilder().disableHtmlEscaping();
builder.excludeFieldsWithoutExposeAnnotation(); //<-- This tells GSON look for @Expose
gson = builder.create();
GsonBuilder=new GsonBuilder().disableHtmlEscaping();
builder.excludeFieldswithout exposeannotation()//修复toString方法是什么意思?这是它的外观:return“User[id=“+id+”,userName=“+userName+”,email=“+email+”,fullName=“+fullName+”,firstName=“+firstName+”,lastName=“+lastName+”,lastLoginDate=“+lastLoginDate+”,applications=“+applications+”); 通过将对象中的对象转换为字符串,您实际上也在对它们调用toString,这最终会对它们的引用等调用toString。您的toString方法实现需要修复-只打印出对象的字符串版本中使用的Primative。尤其要避免不必要地打印收藏。打印集合和关系触发器加载它们(如果它们是惰性的)。
@Retention(RetentionPolicy.RUNTIME)
@Target(value = ElementType.FIELD)
public @interface InvisibleJson {}
@InvisibleJson
@ManyToMany(mappedBy="roles")
public List<Staff> staff;
@Expose
private String name;
@ManyToMany
private List<Users> users
GsonBuilder builder = new GsonBuilder().disableHtmlEscaping();
builder.excludeFieldsWithoutExposeAnnotation(); //<-- This tells GSON look for @Expose
gson = builder.create();