json 使用 jax-rs 和 jpa 的递归循环 stackoverflow
json recursive loop stackoverflow using jax-rs and jpa
我正在以正确的方式获取对象,但 JSON 响应出现了无穷无尽的递归问题。
实体
@Entity
public class ListItem {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToOne (cascade = CascadeType.ALL, fetch = FetchType.EAGER )
private ListItem parentListItem;
@OneToMany (mappedBy ="parentListItem", cascade = CascadeType.ALL, fetch = FetchType.EAGER )
private List<ListItem> childListItemList;
}
道
public ListItem getMenuListById(Long id){
ListItem listItem = em.find(ListItem.class, id);
log("from DAO, listItem parent name: "+ listItem.getName());
List<ListItem> listItemLevel2List = listItem.getChildListItemList();
recurse(listItemLevel2List);
return listItem;
}
public void recurse(List<ListItem> listItemList){
log("from DAO, level2 list item childres size: "+listItemList.size());
if(listItemList.size() > 0){
for(ListItem listItem : listItemList){
log("from DAO, listItem name: "+ listItem.getName());
log(" -> from DAO, listItem parent name: "+ listItem.getParentListItem().getName());
List<ListItem> level2List = listItem.getChildListItemList();
if(level2List.size() > 0){
recurse(level2List);
}
}
}
}
控制器
@GET
@Path("level1")
@Produces ("application/json")
public ListItem getMenuList(){
ListItem listItem = listItemService.getMenuListById(1L);
return listItem;
}
控制台输出:似乎正确
from DAO, listItem parent name: Baby Changing
from DAO, level2 list item childres size: 6
from DAO, listItem name: Changing Mats
-> from DAO, listItem parent name: Baby Changing
from DAO, listItem name: Nappy Stacker
-> from DAO, listItem parent name: Baby Changing
from DAO, listItem name: Potty Training
-> from DAO, listItem parent name: Baby Changing
07:10:37,576 INFO [stdout] (default task-24) from DAO, listItem name: Nappies & Wipes
-> from DAO, listItem parent name: Baby Changing
07:10:37,576 INFO [stdout] (default task-24) from DAO, listItem name: Baby Changing Bags
-> from DAO, listItem parent name: Baby Changing
from DAO, listItem name: Changing Stations
-> from DAO, listItem parent name: Baby Changing
JSON 输出 -- 以错误的方式嵌入长递归对象 --
http://pastebin.com/bHwbN1yh (using paste bin as its too long)
错误
org.jboss.resteasy.spi.UnhandledException: Response is committed, can't handle exception
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (WhosebugError) (through reference chain: goo.entities.ListItem["parentListItem"]->goo.entities.ListItem["childListItemList"]->org.hibernate.collection.internal.PersistentBag[0]->goo.entities.ListItem["parentListItem"]
Caused by: java.lang.WhosebugError
at java.lang.ClassLoader.defineClass1(Native Method)
数据库table - 看起来不错
json 输出视图 - 部分
pom.xml(查看我正在使用的库;只是为了确定)
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>goo</groupId>
<artifactId>goo</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>goo</name>
<build>
<finalName>goo</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<inherited>true</inherited>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey</groupId>
<artifactId>jersey-bom</artifactId>
<version>${jersey.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
<!-- use the following artifactId if you don't need servlet 2.x compatibility -->
<!-- artifactId>jersey-container-servlet</artifactId -->
</dependency>
<!-- uncomment this to get JSON support
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
</dependency>
-->
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
<version>2.22</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.6.2</version>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
<!--<dependency>-->
<!--<groupId>org.jboss.ejb3</groupId>-->
<!--<artifactId>jboss-ejb3-ext-api</artifactId>-->
<!--<version>2.1.0</version>-->
<!--<scope>provided</scope>-->
<!--</dependency>-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.3-1103-jdbc41</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
<version>1.19</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.2.12</version>
</dependency>
</dependencies>
<properties>
<jersey.version>2.21</jersey.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jdk.version>1.7</jdk.version>
<hibernate.version>5.0.1.Final</hibernate.version>
</properties>
</project>
更新
我使用了 @JsonBackReference
和 @JsonManagedReference
注释,但它只是忽略了 childListIemList
@Entity
public class ListItem {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@JsonManagedReference
@ManyToOne (cascade = CascadeType.ALL, fetch = FetchType.EAGER )
private ListItem parentListItem;
@JsonBackReference
@OneToMany (mappedBy = "parentListItem", cascade = CascadeType.ALL, fetch = FetchType.EAGER )
private List<ListItem> childListItemList;
将 @JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id")
放在实体顶部 class 有所帮助。
使用 @JsonBackReference
和 @JsonManagedReference
注释只是忽略了 childListItem
http://wiki.fasterxml.com/JacksonFeatureObjectIdentity
在 Jackson 2.0 之前,循环对象图(或更一般地,共享引用的处理)的处理仅限于 parent/child(双向)引用的特定情况。虽然这可用于支持数据库模型常见的直接一对多和一对一引用,但它不是通用解决方案。
由于 2.0 允许对 API 和内部接口进行更大的更改,因此计划为此版本提供更通用的解决方案
我正在以正确的方式获取对象,但 JSON 响应出现了无穷无尽的递归问题。
实体
@Entity
public class ListItem {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToOne (cascade = CascadeType.ALL, fetch = FetchType.EAGER )
private ListItem parentListItem;
@OneToMany (mappedBy ="parentListItem", cascade = CascadeType.ALL, fetch = FetchType.EAGER )
private List<ListItem> childListItemList;
}
道
public ListItem getMenuListById(Long id){
ListItem listItem = em.find(ListItem.class, id);
log("from DAO, listItem parent name: "+ listItem.getName());
List<ListItem> listItemLevel2List = listItem.getChildListItemList();
recurse(listItemLevel2List);
return listItem;
}
public void recurse(List<ListItem> listItemList){
log("from DAO, level2 list item childres size: "+listItemList.size());
if(listItemList.size() > 0){
for(ListItem listItem : listItemList){
log("from DAO, listItem name: "+ listItem.getName());
log(" -> from DAO, listItem parent name: "+ listItem.getParentListItem().getName());
List<ListItem> level2List = listItem.getChildListItemList();
if(level2List.size() > 0){
recurse(level2List);
}
}
}
}
控制器
@GET
@Path("level1")
@Produces ("application/json")
public ListItem getMenuList(){
ListItem listItem = listItemService.getMenuListById(1L);
return listItem;
}
控制台输出:似乎正确
from DAO, listItem parent name: Baby Changing
from DAO, level2 list item childres size: 6
from DAO, listItem name: Changing Mats
-> from DAO, listItem parent name: Baby Changing
from DAO, listItem name: Nappy Stacker
-> from DAO, listItem parent name: Baby Changing
from DAO, listItem name: Potty Training
-> from DAO, listItem parent name: Baby Changing
07:10:37,576 INFO [stdout] (default task-24) from DAO, listItem name: Nappies & Wipes
-> from DAO, listItem parent name: Baby Changing
07:10:37,576 INFO [stdout] (default task-24) from DAO, listItem name: Baby Changing Bags
-> from DAO, listItem parent name: Baby Changing
from DAO, listItem name: Changing Stations
-> from DAO, listItem parent name: Baby Changing
JSON 输出 -- 以错误的方式嵌入长递归对象 --
http://pastebin.com/bHwbN1yh (using paste bin as its too long)
错误
org.jboss.resteasy.spi.UnhandledException: Response is committed, can't handle exception
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (WhosebugError) (through reference chain: goo.entities.ListItem["parentListItem"]->goo.entities.ListItem["childListItemList"]->org.hibernate.collection.internal.PersistentBag[0]->goo.entities.ListItem["parentListItem"]
Caused by: java.lang.WhosebugError
at java.lang.ClassLoader.defineClass1(Native Method)
数据库table - 看起来不错
json 输出视图 - 部分
pom.xml(查看我正在使用的库;只是为了确定)
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>goo</groupId>
<artifactId>goo</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>goo</name>
<build>
<finalName>goo</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<inherited>true</inherited>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey</groupId>
<artifactId>jersey-bom</artifactId>
<version>${jersey.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
<!-- use the following artifactId if you don't need servlet 2.x compatibility -->
<!-- artifactId>jersey-container-servlet</artifactId -->
</dependency>
<!-- uncomment this to get JSON support
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
</dependency>
-->
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
<version>2.22</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.6.2</version>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
<!--<dependency>-->
<!--<groupId>org.jboss.ejb3</groupId>-->
<!--<artifactId>jboss-ejb3-ext-api</artifactId>-->
<!--<version>2.1.0</version>-->
<!--<scope>provided</scope>-->
<!--</dependency>-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.3-1103-jdbc41</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
<version>1.19</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.2.12</version>
</dependency>
</dependencies>
<properties>
<jersey.version>2.21</jersey.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jdk.version>1.7</jdk.version>
<hibernate.version>5.0.1.Final</hibernate.version>
</properties>
</project>
更新
我使用了 @JsonBackReference
和 @JsonManagedReference
注释,但它只是忽略了 childListIemList
@Entity
public class ListItem {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@JsonManagedReference
@ManyToOne (cascade = CascadeType.ALL, fetch = FetchType.EAGER )
private ListItem parentListItem;
@JsonBackReference
@OneToMany (mappedBy = "parentListItem", cascade = CascadeType.ALL, fetch = FetchType.EAGER )
private List<ListItem> childListItemList;
将 @JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id")
放在实体顶部 class 有所帮助。
使用 @JsonBackReference
和 @JsonManagedReference
注释只是忽略了 childListItem
http://wiki.fasterxml.com/JacksonFeatureObjectIdentity 在 Jackson 2.0 之前,循环对象图(或更一般地,共享引用的处理)的处理仅限于 parent/child(双向)引用的特定情况。虽然这可用于支持数据库模型常见的直接一对多和一对一引用,但它不是通用解决方案。
由于 2.0 允许对 API 和内部接口进行更大的更改,因此计划为此版本提供更通用的解决方案