2012-04-10 15 views
10

Sto usando jackson 1.9.2 con Hibernate/Spring MVC tramite MappingJacksonHttpMessageConverter.Jackson ha confuso la relazione uno-a-uno bidirezionale

Jackson non può serializzare la relazione bidirezionale uno-a-molti e crea un ciclo infinito.

Le classi che sto usando sono:

  • conversazione, che ha una serie di istanze di SMS.

  • Ogni istanza SMS ha una serie di PhoneNumbers

  • Ogni PhoneNumber ha un contatto genitore (questo è il bidirezionale relazione molti-a-uno)

Quello che sto cercando di fare è per serializzare una conversazione.

Se io non uso @JsonManagedReference e @JsonBackReference poi Jackson crashe a causa di un ciclo infinito. Ma quando li uso, il contatto non ottenere serializzato nella PhoneNumber.

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

Il risultato è:

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

anziché

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

risposta

1

Come prima soluzione, ho mantenuto queste annotazioni e creato un altra classe: ContactWithouPhoneNumber e aggiunto come un campo la classe PhoneNumber.

Ora, prima del rendering, copio tutti i campi tranne PhoneNumber, da contatto a contactWithoutPhoneNumber. L'output JSON contiene tutto ciò di cui ho bisogno.

Questo è il modello di progettazione DTO.

0

Una cosa sbagliata nella classe def è l'utilizzo di List untyped; dovresti preferire:

List<PhoneNumber> phoneNumber ; 

poiché altrimenti Jackson non può sapere di che tipo si tratta quando deserializza; e anche la serializzazione potrebbe causare problemi (dato che il tipo di base non è noto con certezza). Quindi vorrei prima risolvere questo problema.

Ma in aggiunta la dipendenza potrebbe essere errata: @JsonManagedReference DEVE essere sempre la prima cosa da serializzare. Se questo non è il caso, non è possibile utilizzare queste annotazioni. Senza vedere oggetti che si sta tentando di serializzare, è difficile conoscerlo con certezza (la definizione POJO e JSON sembrano leggermente spente).

+1

Stavo usando la versione generica, l'editor di stackoverflow ha ingoiato il <. Penso che quello che sta succedendo sia che la @JsonBackReference venga serializzata per prima. – redochka

+0

Ah ok. Sì, sembra più probabile; l'errore sarebbe diverso altrimenti. – StaxMan

7

Recentemente ho incontrato un problema simile: Jackson - serializzazione delle entità con le relazioni birectional (cicli evitando)

Quindi la soluzione è quella di eseguire l'aggiornamento a Jackson 2.0, e aggiungere alle classi la seguente annotazione:

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

Quindi il problema è che Spring non funziona con Jackson 2.0. Questo è stato risolto nel modo seguente:

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

E l'own.implementation.of.MappingJacksonHttpMessageConverter è sulla base di questo:

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

Ma usare ObjectMapper e altre classi Jackson da Jackson 2,0, invece di Jackson 1. *

+1

Grazie, ho appena provato questo e sembra che funzioni solo con la prima conversazione nell'elenco delle conversazioni restituito. Qualche idea? Dove dovrei inserire JsonIdentityInfo? – redochka

+0

È necessario inserire JsonIdentityInfo per entrambe le classi (Contact e PhoneNumber) e rimuovere le annotazioni JsonBack/ManagedReference (per quanto ho capito dalla domanda). –

+0

Quando rimuovo le annotazioni JsonBack/ManagedReference ottengo il seguente errore: com.fasterxml.jackson.databind.JsonMappingException: Class com.fasterxml.jackson.databind.deser.impl.PropertyBasedObjectIdGenerator non ha un costruttore predefinito (no arg) (tramite riferimento chain: java.util.ArrayList [0] -> com.model.Conversation ["smsSet"] ​​-> java.util.LinkedHashSet [0] -> com.model.SmsBean ["phoneNumbers"] -> org.hibernate. collection.PersistentSet [0]) – redochka

0

È possibile aggiungere @JsonIgnore ai campi e il programma di tracciamento salterà su di essi durante la serializzazione. È simile in funzione a @Transient.

È nel jackson-core-asl.

+2

Questa non è proprio una soluzione . Ha bisogno che quei campi vengano serializzati. –

Problemi correlati