web-dev-qa-db-fra.com

Infinite Recursion avec Jackson JSON, Spring MVC 4.2 et Hibernate JPA

Lorsque Spring MVC essaie de convertir un objet JPA associé à une association bidirectionnelle en JSON par jackson 2.6.1, je continue à obtenir

org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: Infinite recursion (StackOverflowError)

et la première entité est:

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;
}
.......
}

la seconde est:

 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;
}

et voici les dépendances:

<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>

J'ai utilisé "@JsonIgnore", "@JsonIdentityInfo" et "XmlTransient" pour empêcher la récursivité, mais ils ne fonctionnent pas tous les deux et le serveur a signalé cette erreur. Est-ce que quelqu'un peut m'aider?

Merci.

Edit: Et trace de pile:

org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: Infinite recursion (StackOverflowError) (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 (StackOverflowError) (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.StackOverflowError
    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)
...

RESOLU: Dans mon entité d'origine, j'ai 5 relations bidirectionnelles mais, juste, j'ai été annoté d'une relation. La raison en est que Tomcat n'a pas imprimé d'exception dans la page de résultats et que je ne vérifie pas le fichier journal Tomcat.

11
mohammad_1m2

Il suffit de mettre @JsonIgnore

@JsonIgnore
@OneToMany(fetch = FetchType.LAZY, mappedBy = "userClass")
public List<User> getUsers() {
     return this.users;
}

Cela ignorera l'objet de chargement paresseux et corrigera votre problème.

Mise à jour

22
Khaled Lela

@JsonIgnore ignore simplement le champ annoté du résultat. Si vous devez également inclure le champ généré par une exception avec le résultat, utilisez @JsonManagedReference, @JsonBackReference conformément au didacticiel suivant. http://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion

Si une classe a plus d'une relation bidirectionnelle, mieux d'utiliser @JsonIdentityInfo

5
Udara Seneviratne

Essayez d’ajouter une annotation @XmlTransient au-dessus du côté de la référence manytoone,

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;
}
 .......
}
0
Nilesh Mistry