Jackson - toveis forhold

1. Oversikt

I denne opplæringen vil vi gå gjennom de beste måtene å håndtere toveis forhold i Jackson.

Vi vil diskutere Jackson JSONs uendelige rekursjonsproblem, så - vi får se hvordan vi kan serieisere enheter med toveis forhold og til slutt - vi vil deserialisere dem.

2. Uendelig rekursjon

Først - la oss ta en titt på Jackson uendelig rekursjonsproblem. I det følgende eksemplet har vi to enheter - “Bruker”Og”Punkt”- med et enkelt en-til-mange forhold:

Bruker”Enhet:

public class User {public int id; offentlig streng navn; public List userItems; }

Punkt”Enhet:

public class Item {public int id; offentlig streng elementnavn; offentlig bruker eier; }

Når vi prøver å serieisere en forekomst av “Punkt“, Vil Jackson kaste en JsonMappingException unntak:

@Test (forventet = JsonMappingException.class) offentlig ugyldig givenBidirectionRelation_whenSerializing_thenException () kaster JsonProcessingException {Bruker bruker = ny bruker (1, "John"); Vareartikkel = nytt element (2, "bok", bruker); user.addItem (vare); ny ObjectMapper (). writeValueAsString (element); }

De fullt unntak er:

com.fasterxml.jackson.databind.JsonMappingException: Uendelig rekursjon (StackOverflowError) (gjennom referansekjede: org.baeldung.jackson.bidirection.Item ["eier"] -> org.baeldung.jackson.bidirection.User ["userItems"] -> java.util.ArrayList [0] -> org.baeldung.jackson.bidirection.Item ["eier"] ->… ..

La oss se i løpet av de neste par avsnittene - hvordan du kan løse dette problemet.

3. Bruk @JsonManagedReference, @JsonBackReference

La oss først kommentere forholdet til @JsonManagedReference, @JsonBackReference for å la Jackson bedre håndtere forholdet:

Her er “Bruker”Enhet:

public class User {public int id; offentlig streng navn; @JsonBackReference offentlig Liste userItems; }

Og "Punkt“:

public class Item {public int id; offentlig streng elementnavn; @JsonManagedReference offentlig bruker eier; }

La oss nå teste ut de nye enhetene:

@Test offentlig ugyldighet gittBidirectionRelation_whenUsingJacksonReferenceAnnotation_thenCorrect () kaster JsonProcessingException {Bruker bruker = ny bruker (1, "John"); Vareartikkel = nytt element (2, "bok", bruker); user.addItem (vare); String result = new ObjectMapper (). WriteValueAsString (item); assertThat (resultat, inneholderString ("bok")); assertThat (resultat, inneholderString ("John")); assertThat (resultat, ikke (inneholderString ("userItems"))); }

Her er utgangen av serialisering:

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

Noter det:

  • @JsonManagedReference er den fremre delen av referansen - den som serielliseres normalt.
  • @JsonBackReference er den bakre delen av referansen - den vil bli utelatt fra serialisering.

4. Bruk @JsonIdentityInfo

Nå - la oss se hvordan vi kan hjelpe med serialisering av enheter med toveis forhold ved hjelp @JsonIdentityInfo.

Vi legger til merknad på klassenivå i vår “Bruker”Enhet:

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

Og til “Punkt”Enhet:

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

Tid for testen:

@Test offentlig ugyldighet gittBidirectionRelation_whenUsingJsonIdentityInfo_thenCorrect () kaster JsonProcessingException {Bruker bruker = ny bruker (1, "John"); Vareartikkel = nytt element (2, "bok", bruker); user.addItem (vare); String result = new ObjectMapper (). WriteValueAsString (item); assertThat (resultat, inneholderString ("bok")); assertThat (resultat, inneholderString ("John")); assertThat (resultat, containString ("userItems")); }

Her er produksjonen av serialisering:

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

5. Bruk @JsonIgnore

Alternativt kan vi også bruke @JsonIgnore kommentar til ganske enkelt ignorere en av sidene i forholdet, og dermed bryte kjeden.

I det følgende eksemplet - vil vi forhindre den uendelige rekursjonen ved å ignorere “Bruker”Eiendom“userItems”Fra serialisering:

Her er "Bruker”Enhet:

public class User {public int id; offentlig streng navn; @JsonIgnorer offentlig Liste userItems; }

Og her er testen vår:

@Test public void givenBidirectionRelation_whenUsingJsonIgnore_thenCorrect () kaster JsonProcessingException {Bruker bruker = ny bruker (1, "John"); Vareartikkel = nytt element (2, "bok", bruker); user.addItem (vare); String result = new ObjectMapper (). WriteValueAsString (item); assertThat (resultat, inneholderString ("bok")); assertThat (resultat, inneholderString ("John")); assertThat (resultat, ikke (inneholderString ("userItems"))); }

Og her er produksjonen av serialisering:

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

6. Bruk @JsonView

Vi kan også bruke det nyere @JsonView kommentar for å ekskludere den ene siden av forholdet.

I det følgende eksemplet - bruker vi to JSON-visninger - Offentlig og Innvendig hvor Innvendig strekker Offentlig:

offentlig klasse Visninger {offentlig statisk klasse Offentlig {} offentlig statisk klasse Internt utvider Offentlig {}}

Vi inkluderer alle Bruker og Punkt felt i Offentlig Utsikt - bortsett fra Bruker felt userItems som vil bli inkludert i Innvendig Utsikt:

Her er vår enhet “Bruker“:

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

Og her er vår enhet “Punkt“:

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

Når vi serierer ved hjelp av Offentlig visning, det fungerer riktig - fordi vi ekskluderte userItems fra å bli seriellisert:

@Test offentlig ugyldighet gittBidirectionRelation_whenUsingPublicJsonView_thenCorrect () kaster JsonProcessingException {Bruker bruker = ny bruker (1, "John"); Vareartikkel = nytt element (2, "bok", bruker); user.addItem (vare); String result = new ObjectMapper (). WriterWithView (Views.Public.class) .writeValueAsString (item); assertThat (resultat, inneholderString ("bok")); assertThat (resultat, inneholderString ("John")); assertThat (resultat, ikke (inneholderString ("userItems"))); }

Men hvis vi serierer ved hjelp av en Innvendig utsikt, JsonMappingException kastes fordi alle feltene er inkludert:

@Test (forventet = JsonMappingException.class) offentlig ugyldig givenBidirectionRelation_whenUsingInternalJsonView_thenException () kaster JsonProcessingException {Bruker bruker = ny bruker (1, "John"); Vareartikkel = nytt element (2, "bok", bruker); user.addItem (vare); ny ObjectMapper () .writerWithView (Views.Internal.class) .writeValueAsString (element); }

7. Bruk en Custom Serializer

Neste - la oss se hvordan vi kan serieisere enheter med toveis forhold ved hjelp av en tilpasset serializer.

I det følgende eksemplet - vil vi bruke en tilpasset serielliseringsenhet til å serieisere “Bruker”Eiendom“userItems“:

Her er “Bruker”Enhet:

public class User {public int id; offentlig streng navn; @JsonSerialize (ved hjelp av = CustomListSerializer.class) public List userItems; }

Og her er “CustomListSerializer“:

offentlig klasse CustomListSerializer utvider 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); }}

La oss nå teste ut serialisereren og se den riktige typen utdata som produseres:

@Test offentlig ugyldighet gittBidirectionRelation_whenUsingCustomSerializer_thenCorrect () kaster JsonProcessingException {Bruker bruker = ny bruker (1, "John"); Vareartikkel = nytt element (2, "bok", bruker); user.addItem (vare); String result = new ObjectMapper (). WriteValueAsString (item); assertThat (resultat, inneholderString ("bok")); assertThat (resultat, inneholderString ("John")); assertThat (resultat, containString ("userItems")); }

Og den endelige produksjonen av serialiseringen med den tilpassede serialisereren:

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

8. Deserialiser med @JsonIdentityInfo

Nå - la oss se hvordan du avserialiserer enheter med toveis forhold ved hjelp av @JsonIdentityInfo.

Her er "Bruker”Enhet:

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

Og "Punkt”Enhet:

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

La oss nå skrive en rask test - startende med noen manuelle JSON-data vi vil analysere og avslutte med riktig konstruert enhet:

@Test offentlig ugyldighet gittBidirectionRelation_whenDeserializingWithIdentity_thenCorrect () kaster JsonProcessingException, IOException {String json = "{\" id \ ": 2, \" itemName \ ": \" book \ ", \" eier \ ": {\" id \ ": 1, \ "name \": \ "John \", \ "userItems \": [2]}} "; ItemWithIdentity item = new ObjectMapper (). ReaderFor (ItemWithIdentity.class) .readValue (json); assertEquals (2, item.id); assertEquals ("bok", item.itemName); assertEquals ("John", item.owner.name); }

9. Bruk Custom Deserializer

Til slutt, la oss deserialisere enhetene med toveis forhold med en tilpasset deserializer.

I det følgende eksemplet - vil vi bruke tilpasset deserializer til å analysere “Bruker”Eiendom“userItems“:

Her er “Bruker”Enhet:

public class User {public int id; offentlig streng navn; @JsonDeserialize (ved hjelp av = CustomListDeserializer.class) public List userItems; }

Og her er vår “CustomListDeserializer“:

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

Og den enkle testen:

@Test offentlig ugyldighet gittBidirectionRelation_whenUsingCustomDeserializer_thenCorrect () kaster JsonProcessingException, IOException {String json = "{\" id \ ": 2, \" itemName \ ": \" book \ ", \" eier \ ": {\" id \ ": 1, \ "name \": \ "John \", \ "userItems \": [2]}} "; Element element = ny ObjectMapper (). ReaderFor (Item.class) .readValue (json); assertEquals (2, item.id); assertEquals ("book", item.itemName); assertEquals ("John", item.owner.name); }

10. Konklusjon

I denne opplæringen illustrerte vi hvordan du serialiserer / deserialiserer enheter med toveis relasjoner ved hjelp av Jackson.

Implementeringen av alle disse eksemplene og kodebiter kan du finne i GitHub-prosjektet vårt - dette er et Maven-basert prosjekt, så det skal være enkelt å importere og kjøre som det er.


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