Jackson - tovejsforhold

1. Oversigt

I denne vejledning gennemgår vi de bedste måder at håndtere tovejsforhold i Jackson.

Vi diskuterer Jackson JSON's uendelige rekursionsproblem, så - vi ser, hvordan vi serierer enheder med tovejsforhold, og endelig - vi deserialiserer dem.

2. Uendelig rekursion

Først - lad os se på det uendelige rekursionsproblem i Jackson. I det følgende eksempel har vi to enheder - “Bruger”Og“Vare”- med et simpelt en-til-mange forhold:

Det "Bruger" enhed:

public class User {public int id; offentligt strengnavn; offentlig liste userItems; }

Det "Vare" enhed:

public class Item {public int id; public String itemName; offentlig Bruger ejer; }

Når vi forsøger at serieisere en forekomst af “Vare“, Vil Jackson kaste et JsonMappingException undtagelse:

@Test (forventet = JsonMappingException.class) offentlig ugyldighed givenBidirectionRelation_whenSerializing_thenException () kaster JsonProcessingException {Brugerbruger = ny bruger (1, "John"); Item item = new Item (2, "book", user); user.addItem (vare); ny ObjectMapper (). writeValueAsString (element); }

Det fuld undtagelse er:

com.fasterxml.jackson.databind.JsonMappingException: Uendelig rekursion (StackOverflowError) (gennem referencekæde: org.baeldung.jackson.bidirection.Item ["ejer"] -> org.baeldung.jackson.bidirection.User ["userItems"] -> java.util.ArrayList [0] -> org.baeldung.jackson.bidirection.Item ["ejer"] ->… ..

Lad os se i løbet af de næste par afsnit - hvordan man løser dette problem.

3. Brug @JsonManagedReference, @JsonBackReference

Lad os først kommentere forholdet til @JsonManagedReference, @JsonBackReference at lade Jackson bedre håndtere forholdet:

Her er “Bruger" enhed:

public class User {public int id; offentligt strengnavn; @JsonBackReference offentlig liste userItems; }

Og "Vare“:

public class Item {public int id; public String itemName; @JsonManagedReference offentlig bruger ejer; }

Lad os nu teste de nye enheder:

@Test offentlig ugyldighed givenBidirectionRelation_whenUsingJacksonReferenceAnnotation_thenCorrect () kaster JsonProcessingException {Bruger bruger = ny bruger (1, "John"); Item item = new Item (2, "book", user); user.addItem (vare); String result = new ObjectMapper (). WriteValueAsString (item); assertThat (resultat, containString ("bog")); assertThat (resultat, indeholderString ("John")); assertThat (resultat, ikke (indeholderString ("userItems"))); }

Her er output af serialisering:

{"id": 2, "itemName": "book", "owner": {"id": 1, "name": "John"}}

Noter det:

  • @JsonManagedReference er den forreste del af referencen - den, der bliver normaliseret normalt.
  • @JsonBackReference er den bageste del af referencen - den udelades fra serialisering.

4. Brug @JsonIdentityInfo

Lad os nu se, hvordan vi hjælper med serialisering af enheder med tovejsforhold ved hjælp af @JsonIdentityInfo.

Vi tilføjer klasseanmeldelsen til vores “Bruger" enhed:

@JsonIdentityInfo (generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") offentlig klasse bruger {...}

Og til “Vare" enhed:

@JsonIdentityInfo (generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") offentlig klasse Element {...}

Tid til testen:

@Test offentlig ugyldighed givenBidirectionRelation_whenUsingJsonIdentityInfo_thenCorrect () kaster JsonProcessingException {Bruger bruger = ny bruger (1, "John"); Item item = new Item (2, "book", user); user.addItem (vare); String result = new ObjectMapper (). WriteValueAsString (item); assertThat (resultat, containString ("bog")); assertThat (resultat, indeholderString ("John")); assertThat (resultat, containString ("userItems")); }

Her er output af serialisering:

{"id": 2, "itemName": "book", "owner": {"id": 1, "name": "John", "userItems": [2]}}

5. Brug @JsonIgnorer

Alternativt kan vi også bruge @JsonIgnorer kommentar til simpelthen ignorere en af ​​siderne i forholdetog dermed bryde kæden.

I det følgende eksempel - vi forhindrer den uendelige rekursion ved at ignorere “Bruger”Ejendom“userItems”Fra serialisering:

Her er "Bruger" enhed:

public class User {public int id; offentligt strengnavn; @JsonIgnorer offentlig liste userItems; }

Og her er vores test:

@Test offentlig ugyldighed givenBidirectionRelation_whenUsingJsonIgnore_thenCorrect () kaster JsonProcessingException {Bruger bruger = ny bruger (1, "John"); Item item = new Item (2, "book", user); user.addItem (vare); String result = new ObjectMapper (). WriteValueAsString (item); assertThat (resultat, containString ("bog")); assertThat (resultat, indeholderString ("John")); assertThat (resultat, ikke (indeholderString ("userItems"))); }

Og her er output af serialisering:

{"id": 2, "itemName": "book", "owner": {"id": 1, "name": "John"}}

6. Brug @JsonView

Vi kan også bruge det nyere @JsonView kommentar for at udelukke den ene side af forholdet.

I det følgende eksempel bruger vi to JSON-udsigter - Offentlig og Indre hvor Indre strækker sig Offentlig:

offentlig klasse Visninger {offentlig statisk klasse Offentlig {} offentlig statisk klasse Intern udvider Offentlig {}}

Vi inkluderer alle Bruger og Vare felter i Offentlig Udsigt - undtagen Bruger Mark userItems som vil blive inkluderet i Indre Udsigt:

Her er vores enhed “Bruger“:

public class User {@JsonView (Views.Public.class) public int id; @JsonView (Views.Public.class) offentligt strengnavn; @JsonView (Views.Internal.class) offentlig liste userItems; }

Og her er vores enhed “Vare“:

public class Item {@JsonView (Views.Public.class) public int id; @JsonView (Views.Public.class) public String itemName; @JsonView (Views.Public.class) offentlig brugerejer; }

Når vi serieliseres ved hjælp af Offentlig se, det fungerer korrekt - fordi vi udelukkede userItems fra at blive serieliseret:

@Test offentlig ugyldighed givenBidirectionRelation_whenUsingPublicJsonView_thenCorrect () kaster JsonProcessingException {Bruger bruger = ny bruger (1, "John"); Item item = new Item (2, "book", user); user.addItem (vare); String result = new ObjectMapper (). WriterWithView (Views.Public.class) .writeValueAsString (item); assertThat (resultat, containString ("bog")); assertThat (resultat, indeholderString ("John")); assertThat (resultat, ikke (indeholderString ("userItems"))); }

Men hvis vi serieliseres ved hjælp af en Indre udsigt, JsonMappingException kastes, fordi alle felter er inkluderet:

@Test (forventet = JsonMappingException.class) offentlig ugyldighed givenBidirectionRelation_whenUsingInternalJsonView_thenException () kaster JsonProcessingException {Brugerbruger = ny bruger (1, "John"); Item item = new Item (2, "book", user); user.addItem (vare); ny ObjectMapper () .writerWithView (Views.Internal.class) .writeValueAsString (item); }

7. Brug en Custom Serializer

Dernæst - lad os se, hvordan vi serierer enheder med tovejsforhold ved hjælp af en tilpasset serializer.

I det følgende eksempel - vi bruger en brugerdefineret serializer til at serialisere “Bruger”Ejendom“userItems“:

Her er “Bruger" enhed:

public class User {public int id; offentligt strengnavn; @JsonSerialize (ved hjælp af = CustomListSerializer.class) offentlig liste userItems; }

Og her er “CustomListSerializer“:

offentlig klasse CustomListSerializer udvider StdSerializer{public CustomListSerializer () {this (null); } offentlig CustomListSerializer (klasse t) {super (t); } @Override public void serialize (List items, JsonGenerator generator, SerializerProvider provider) kaster IOException, JsonProcessingException {List ids = new ArrayList (); for (Item item: items) {ids.add (item.id); } generator.writeObject (ids); }}

Lad os nu teste serienummeret og se den rigtige type output, der produceres:

@Test offentlig ugyldighed givenBidirectionRelation_whenUsingCustomSerializer_thenCorrect () kaster JsonProcessingException {Bruger bruger = ny bruger (1, "John"); Item item = new Item (2, "book", user); user.addItem (vare); String result = new ObjectMapper (). WriteValueAsString (item); assertThat (resultat, containString ("bog")); assertThat (resultat, indeholderString ("John")); assertThat (resultat, containString ("userItems")); }

Og den endelige output af serialisering med den tilpassede serializer:

{"id": 2, "itemName": "book", "owner": {"id": 1, "name": "John", "userItems": [2]}}

8. Deserialiser med @JsonIdentityInfo

Lad os nu se, hvordan man deserialiserer enheder med tovejsforhold ved hjælp af @JsonIdentityInfo.

Her er "Bruger" enhed:

@JsonIdentityInfo (generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") offentlig klasse bruger {...}

Og "Vare" enhed:

@JsonIdentityInfo (generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") offentlig klasse Element {...}

Lad os nu skrive en hurtig test - startende med nogle manuelle JSON-data, vi vil analysere og afslutte med den korrekt konstruerede enhed:

@Test offentlig ugyldighed givenBidirectionRelation_whenDeserializingWithIdentity_thenCorrect () kaster JsonProcessingException, IOException {String json = "{\" id \ ": 2, \" itemName \ ": \" bog \ ", \" ejer \ ": {\" id \ ": 1, \ "navn \": \ "John \", \ "userItems \": [2]}} "; ItemWithIdentity item = new ObjectMapper (). ReaderFor (ItemWithIdentity.class) .readValue (json); assertEquals (2, item.id); assertEquals ("bog", item.itemName); assertEquals ("John", item.owner.name); }

9. Brug Custom Deserializer

Endelig lad os deserialisere enhederne med tovejsforhold ved hjælp af en brugerdefineret deserializer.

I det følgende eksempel - vi bruger brugerdefineret deserializer til at analysere “Bruger”Ejendom“userItems“:

Her er “Bruger" enhed:

public class User {public int id; offentligt strengnavn; @JsonDeserialize (ved hjælp af = CustomListDeserializer.class) public List userItems; }

Og her er vores “CustomListDeserializer“:

offentlig klasse CustomListDeserializer udvider StdDeserializer{public CustomListDeserializer () {this (null); } offentlig CustomListDeserializer (klasse vc) {super (vc); } @Override public List deserialize (JsonParser jsonparser, DeserializationContext context) kaster IOException, JsonProcessingException {returner ny ArrayList (); }}

Og den enkle test:

@Test offentlig ugyldighed givenBidirectionRelation_whenUsingCustomDeserializer_thenCorrect () kaster JsonProcessingException, IOException {String json = "{\" id \ ": 2, \" itemName \ ": \" bog \ ", \" ejer \ ": {\" id \ ": 1, \ "navn \": \ "John \", \ "userItems \": [2]}} "; Item item = new ObjectMapper (). ReaderFor (Item.class) .readValue (json); assertEquals (2, item.id); assertEquals ("bog", item.itemName); assertEquals ("John", item.owner.name); }

10. Konklusion

I denne vejledning illustrerede vi, hvordan du serialiserer / deserialiserer enheder med tovejsforhold ved hjælp af Jackson.

Implementeringen af ​​alle disse eksempler og kodestykker kan findes i vores GitHub-projekt - dette er et Maven-baseret projekt, så det skal være let at importere og køre som det er.


$config[zx-auto] not found$config[zx-overlay] not found