2012-04-10 30 views
10

Estoy usando jackson 1.9.2 con Hibernate/Spring MVC a través de MappingJacksonHttpMessageConverter.Jackson confundido con una relación uno a muchos bidireccional

Jackson no puede serializar la relación uno a muchos bidireccional y crea un bucle infinito.

Las clases que estoy usando son:

  • conversación que tiene un conjunto de instancias de SMS.

  • Cada instancia de SMS tiene un conjunto de números telefónicos

  • Cada Fax tiene un contacto con los padres (este es el bidireccional relación muchos-a-uno)

Lo que estoy tratando de hacer es para serializar una conversación.

Si yo no uso @JsonManagedReference y @JsonBackReference continuación Jackson crashe debido a un bucle infinito. Pero cuando las uso, la Contacto no recibe serializa en la Fax.

 
Class Contact { 
    @JsonManagedReference 
    List<PhoneNumber> phoneNumber ; 
} 
Class PhoneNumber { 
    @JsonBackReference 
    Contact contact; 
} 

La salida es:

 
{ <--------------------- Conversation 
    "id": 51, 
    "smsSet": [ 
     { 
     "id": 53, 
     "origin":, 
     "destination": "06533844XY", 
     "message": "Hello world!", 
     "phoneNumbers": [ 
      { 
      "id": 64, 
      "num": "06533844XY", 
      "creationDate": 1333992533000, 
      } 
     ], 
     } 
    ], 
    "creationDate": 1333992534000 
    } 

en lugar de

 
{ <---------- conversation 
    "id": 51, 
    "smsSet": [ 
     { 
     "id": 53, 
     "origin":, 
     "destination": "06533844XY", 
     "message": "Hello world!", 
     "phoneNumbers": [ 
      { 
      "id": 64, 
      "num": "06533844XY", 
      "creationDate": 1333992533000, 
      "contact": <--------------------- Missing part 
      { 
       "id": 12, 
       "name": "Samuel Jackson", 
       "primaryNumber": "06533844XY" 
      } 
      } 
     ], 
     } 
    ], 
    "creationDate": 1333992534000 
    } 

Respuesta

1

Como una primera solución, no dejaba de estas anotaciones y creó una otra clase: ContactWithouPhoneNumber y añadido como un campo de la clase PhoneNumber.

Ahora, antes de la representación, copio todos los campos excepto PhoneNumber, de contact a contactWithoutPhoneNumber. La salida JSON contiene todo lo que necesito.

Este es el patrón de diseño DTO.

0

Una cosa incorrecta en su clase def es el uso de List sin tipo; debería tener:

List<PhoneNumber> phoneNumber ; 

, de lo contrario, Jackson no puede saber de qué tipo es cuando deserializa; e incluso al serializarlo podría causar problemas (ya que no se conoce con certeza el tipo de base). Así que primero solucionaría este problema.

Pero, además, su dependencia puede ser incorrecta: @JsonManagedReference DEBE ser siempre el primero en serializar. Si este no es el caso, no puede usar estas anotaciones. Sin ver los objetos que intenta serializar, es difícil saberlo con certeza (la definición POJO y JSON parecen un poco apagados).

+1

Estaba usando la versión genérica, el editor de stackoverflow se ha tragado el <. Creo que lo que está sucediendo es que el @JsonBackReference está siendo serializado primero. – redochka

+0

Ah bien. Sí, eso parece más probable; el error sería diferente de lo contrario. – StaxMan

7

me encontré recientemente un problema similar: Jackson - serialización de entidades con relaciones birectional (ciclos evitando)

Así que la solución es actualizar a Jackson 2,0, y añadir a las clases de la siguiente anotación:

@JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class, 
        property = "@id") 
public class SomeEntityClass ... 

Luego, el problema es que Spring no funciona con Jackson 2.0. Esto ha sido resuelto de la siguiente manera:

<bean id="jacksonMessageConverter" 
      class="own.implementation.of.MappingJacksonHttpMessageConverter"/> 

<bean class="org.springframework.web.servlet.mvc 
      .annotation.AnnotationMethodHandlerAdapter"> 
     <property name="messageConverters"> 
      <list> 
       <ref bean="jacksonMessageConverter"/> 
      </list> 
     </property> 
     <property name="requireSession" value="false"/> 
    </bean> 

Y el own.implementation.of.MappingJacksonHttpMessageConverter está basado en esto:

http://www.jarvana.com/jarvana/view/org/springframework/spring-web/3.0.0.RELEASE/spring-web-3.0.0.RELEASE-sources.jar!/org/springframework/http/converter/json/MappingJacksonHttpMessageConverter.java?format=ok

Pero utilizar ObjectMapper y otras clases de Jackson Jackson 2.0 en vez de Jackson 1. *

+1

Gracias, acabo de probar esto, y parece estar funcionando solo con la primera conversación en la lista de conversaciones devuelta. ¿Alguna idea? ¿Dónde debería poner el JsonIdentityInfo? – redochka

+0

Debe colocar JsonIdentityInfo para ambas clases (Contact y PhoneNumber) y eliminar las anotaciones JsonBack/ManagedReference (por lo que entiendo de su pregunta). –

+0

Cuando elimino las anotaciones de JsonBack/ManagedReference aparece el siguiente error: com.fasterxml.jackson.databind.JsonMappingException: Class com.fasterxml.jackson.databind.deser.impl.PropertyBasedObjectIdGenerator no tiene ningún constructor predeterminado (sin arg) (a través de referencia cadena: java.util.ArrayList [0] -> com.model.Conversation ["smsSet"] ​​-> java.util.LinkedHashSet [0] -> com.model.SmsBean ["phoneNumbers"] -> org.hibernate. collection.PersistentSet [0]) – redochka

0

Puede agregar @JsonIgnore a los campos y el asignador omitirá durante la serialización. Es similar en función a @Transient.

Está en el jackson-core-asl.

+2

Esto no es realmente una solución . Él necesita esos campos para ser serializados. –

Cuestiones relacionadas