2012-04-10 10 views
10

Ich benutze Jackson 1.9.2 mit Hibernate/Spring MVC durch MappingJacksonHttpMessageConverter.Jackson mit bidirektionalen Eins-zu-viele-Beziehung verwechselt

Jackson kann keine bidirektionale Eins-zu-viele-Beziehung serialisieren und erstellt eine Endlosschleife.

Die Klassen Ich verwende sind:

  • Conversation, die eine Reihe von SMS-Instanzen hat.

  • Jede SMS-Instanz hat eine Reihe von Phonenumbers

  • Jeder Phone hat einen Mutterkontakt (dies ist die bidirektionale Viele-zu-Eins-Beziehung)

Was ich versuche zu tun, um eine Konversation zu serialisieren.

Wenn ich nicht @JsonManagedReference verwenden und @JsonBackReference dann jackson aufgrund einer Endlosschleife crashe. Aber wenn ich sie verwende, wird die Kontakt nicht in die PhoneNumber serialisiert.

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

Der Ausgang ist:

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

anstelle von

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

Antwort

1

Als erste Lösung, gehalten ich diese Annotationen und erstellt eine andere Klasse: ContactWithouPhoneNumber und hinzugefügt, um es als ein Feld zu die PhoneNumber-Klasse.

Jetzt, vor dem Rendern, kopiere ich alle Felder außer PhoneNumber, von Kontakt zu ContactWithoutPhoneNumber. Die Ausgabe JSON enthält alles, was ich brauche.

Dies ist das DTO-Entwurfsmuster.

0

Eine Sache falsch in Ihrer Klasse def ist die Verwendung von untypisierten List; Sie sollten lieber haben:

da sonst Jackson kann nicht wissen, was der Typ ist beim Deserialisieren; und sogar beim Serialisieren könnte es Probleme verursachen (da der Basistyp nicht sicher bekannt ist). Also würde ich zuerst dieses Problem beheben.

Aber zusätzlich Ihre Abhängigkeit möglicherweise falsch herum: @JsonManagedReference MUSS immer das erste Ding zu serialisieren sein. Wenn dies nicht der Fall ist, können Sie diese Anmerkungen nicht verwenden. Ohne Objekte zu sehen, die Sie versuchen zu serialisieren, ist es schwer zu wissen (POJO-Definition und JSON scheinen etwas aus).

+1

Ich benutzte die generische Version, Stackoverflow-Editor hat die redochka

+0

Ah ok. Ja, das scheint wahrscheinlicher; Der Fehler wäre sonst anders. – StaxMan

7

Ich traf vor kurzem ein ähnliches Problem: Jackson - Serialisierung von Entitäten mit birectional Beziehungen (Vermeidung von Zyklen)

So ist die Lösung nach Jackson 2.0 zu aktualisieren und fügen Sie die folgende Anmerkung zu den Klassen:

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

Dann ist das Problem, dass Spring nicht mit Jackson 2.0 funktioniert. Dies wurde auf folgende Weise gelöst:

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

Und der own.implementation.of.MappingJacksonHttpMessageConverter basiert auf diesem:

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

Aber verwenden ObjectMapper und andere Jackson Klassen von Jackson 2,0 statt von Jackson 1. *

+1

Danke, habe das gerade versucht und es scheint nur mit der ersten Konversation in der zurückgegebenen Konversationsliste zu arbeiten. Irgendeine Idee? Wo sollte ich die JsonIdentityInfo platzieren? – redochka

+0

Sie müssen JsonIdentityInfo für beide Klassen (Kontakt und PhoneNumber) setzen und JsonBack/ManagedReference Annotationen entfernen (soweit ich aus Ihrer Frage verstanden habe). –

+0

Wenn ich die JsonBack/ManagedReference-Annotationen entferne, erhalte ich den folgenden Fehler: com.fasterxml.jackson.databind.JsonMappingException: Class com.fasterxml.jackson.databind.deser.impl.PropertyBasedObjectIdGenerator hat keinen Standardkonstruktor (kein Arg) (durch Referenz Kette: java.util.ArrayList [0] -> com.model.Conversation ["smsSet"] ​​-> java.util.LinkedHashSet [0] -> com.model.SmsBean ["phoneNumbers"] -> org.hibernate. collection.PersistentSet [0]) – redochka

0

Sie können @JsonIgnore zu Feldern hinzufügen, und der Mapper überspringt sie während der Serialisierung. Es ähnelt der Funktion @Transient.

Es ist in der Jackson-Core-asl.

+2

Dies ist nicht wirklich eine Lösung . Er benötigt diese Felder, um sie zu serialisieren. –

Verwandte Themen