When Spring MVC try to convert a JPA object that has a bi-directional association into JSON by jackson 2.6.1 , I keep getting
当Spring MVC试图通过jackson 2.6.1将具有双向关联的JPA对象转换为JSON时,我不断获得
org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: Infinite recursion (*Error)
and first entity is:
第一个实体是:
import com.fasterxml.jackson.annotation.JsonManagedReference;
import javax.persistence.Entity;
import javax.persistence.Table;
...
@Entity
@Table(name = "user")
public class User implements java.io.Serializable {
private Integer userId;
@JsonManagedReference
private UserClass userClass;
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "userId", unique = true, nullable = false)
public Integer getUserId() {
return this.userId;
}
@ManyToOne()
@JoinColumn(name = "userClassId")
public UserClass getUserClass() {
return this.userClass;
}
.......
}
the second is:
第二个是:
import com.fasterxml.jackson.annotation.JsonManagedReference;
import javax.persistence.Entity;
import javax.persistence.Table;
...
@Entity
@Table(name = "user_class")
public class UserClass implements java.io.Serializable {
private Integer userClassId;
@JsonBackReference
private List<User> users = new ArrayList<User>(0);
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "userClassId", unique = true, nullable = false)
public Integer getUserClassId() {
return this.userClassId;
}
@OneToMany(fetch = FetchType.LAZY, mappedBy = "userClass")
public List<User> getUsers() {
return this.users;
}
and here is dependencies:
这是依赖:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>4.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>4.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.8.2.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<scope>provided</scope>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-hibernate4</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.34</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.3.10.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.3.10.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.1.3.Final</version>
</dependency>
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-core</artifactId>
<version>3.0.5</version>
</dependency>
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-jsp</artifactId>
<version>3.0.5</version>
</dependency>
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-api</artifactId>
<version>3.0.5</version>
</dependency>
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-template</artifactId>
<version>3.0.5</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.12</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.12</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.12</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
</dependencies>
I used "@JsonIgnore", "@JsonIdentityInfo" and "XmlTransient" for prevent recursion but both of them not working and the server report this error. Can someone help me?
我使用“@JsonIgnore”,“@ JsonIdentityInfo”和“XmlTransient”来防止递归,但它们都不起作用,服务器报告此错误。有人能帮我吗?
Thanks.
谢谢。
Edit: And Stack trace:
编辑:和堆栈跟踪:
org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: Infinite recursion (*Error) (through reference chain:
sss.com.model.UserClass["users"]->org.hibernate.collection.internal.PersistentBag[0]->sss.com.model.User["userClass"]->sss.com.model.UserClass["users"]->
org.hibernate.collection.internal.PersistentBag[0]->sss.com.model.User["userClass"]->sss.com.model.UserClass["users"]->org.hibernate.collection.internal.PersistentBag[0]->sss.com.model.User["userClass"]->sss.com.model.UserClass["users"]... .
nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (*Error) (through reference chain:
sss.com.model.UserClass["users"]->org.hibernate.collection.internal.PersistentBag[0]->sss.com.model.User["userClass"]->sss.com.model.UserClass["users"]->
org.hibernate.collection.internal.PersistentBag[0]->sss.com.model.User["userClass"]->sss.com.model.UserClass["users"]->org.hibernate.collection.internal.PersistentBag[0]->sss.com.model.User["userClass"]->sss.com.model.UserClass["users"]... . with root cause
java.lang.*Error
at java.io.IOException.<init>(IOException.java:58)
at com.fasterxml.jackson.core.JsonProcessingException.<init>(JsonProcessingException.java:25)
at com.fasterxml.jackson.core.JsonProcessingException.<init>(JsonProcessingException.java:41)
at com.fasterxml.jackson.databind.JsonMappingException.<init>(JsonMappingException.java:143)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:689)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:157)
at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:149)
at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:111)
at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:24)
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:656)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:675)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:157)
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:656)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:675)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:157)
at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:149)
at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:111)
at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:24)
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:656)
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:675)
...
SOLVED: In my original entity I have 5 bidirectional relation but, just, I was annotated one relation. The reason is tomcat didn't print exception in result page and i don't check tomcat log file.
求助:在我的原始实体中,我有5个双向关系,但是,我只注释了一个关系。原因是tomcat没有在结果页面中打印异常而且我没有检查tomcat日志文件。
3 个解决方案
#1
17
Just put @JsonIgnore
只要把@JsonIgnore
@JsonIgnore
@OneToMany(fetch = FetchType.LAZY, mappedBy = "userClass")
public List<User> getUsers() {
return this.users;
}
This will ignore lazy load object and fix your issue.
这将忽略延迟加载对象并修复您的问题。
Update
更新
- According to Udara Seneviratne answer, You can handle
bi-directional relationship
by@JsonManagedReference, @JsonBackReference
. - 根据Udara Seneviratne的回答,您可以通过@JsonManagedReference,@ JsonBackReference处理双向关系。
#2
5
@JsonIgnore just ignore the annotated field from the result. If you need to include exception caused field also with the result, use @JsonManagedReference, @JsonBackReference according to following tutorial. http://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion
@JsonIgnore只是忽略结果中带注释的字段。如果您还需要在结果中包含异常引用字段,请根据以下教程使用@JsonManagedReference,@ JsonBackReference。 http://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion
If a class has more than one bi-directional relationships, better to use @JsonIdentityInfo
如果一个类有多个双向关系,最好使用@JsonIdentityInfo
#3
0
Try to add @XmlTransient annotation above manytoone reference side ,
尝试在多个参考端上方添加@XmlTransient注释,
import com.fasterxml.jackson.annotation.JsonManagedReference;
import javax.persistence.Entity;
import javax.persistence.Table;
...
@Entity
@Table(name = "user")
public class User implements java.io.Serializable {
private Integer userId;
@JsonManagedReference
private UserClass userClass;
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "userId", unique = true, nullable = false)
public Integer getUserId() {
return this.userId;
}
@XmlTransient
@ManyToOne()
@JoinColumn(name = "userClassId")
public UserClass getUserClass() {
return this.userClass;
}
.......
}
#1
17
Just put @JsonIgnore
只要把@JsonIgnore
@JsonIgnore
@OneToMany(fetch = FetchType.LAZY, mappedBy = "userClass")
public List<User> getUsers() {
return this.users;
}
This will ignore lazy load object and fix your issue.
这将忽略延迟加载对象并修复您的问题。
Update
更新
- According to Udara Seneviratne answer, You can handle
bi-directional relationship
by@JsonManagedReference, @JsonBackReference
. - 根据Udara Seneviratne的回答,您可以通过@JsonManagedReference,@ JsonBackReference处理双向关系。
#2
5
@JsonIgnore just ignore the annotated field from the result. If you need to include exception caused field also with the result, use @JsonManagedReference, @JsonBackReference according to following tutorial. http://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion
@JsonIgnore只是忽略结果中带注释的字段。如果您还需要在结果中包含异常引用字段,请根据以下教程使用@JsonManagedReference,@ JsonBackReference。 http://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion
If a class has more than one bi-directional relationships, better to use @JsonIdentityInfo
如果一个类有多个双向关系,最好使用@JsonIdentityInfo
#3
0
Try to add @XmlTransient annotation above manytoone reference side ,
尝试在多个参考端上方添加@XmlTransient注释,
import com.fasterxml.jackson.annotation.JsonManagedReference;
import javax.persistence.Entity;
import javax.persistence.Table;
...
@Entity
@Table(name = "user")
public class User implements java.io.Serializable {
private Integer userId;
@JsonManagedReference
private UserClass userClass;
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "userId", unique = true, nullable = false)
public Integer getUserId() {
return this.userId;
}
@XmlTransient
@ManyToOne()
@JoinColumn(name = "userClassId")
public UserClass getUserClass() {
return this.userClass;
}
.......
}