Jackson-unntak - problemer og løsninger

1. Oversikt

I denne opplæringen vil vi gå over de vanligste Jackson-unntakene - den JsonMappingException og UnrecognizedPropertyException.

Til slutt - vi vil kort diskutere Jackson ingen slike metodefeil.

2. “JsonMappingException: Kan ikke konstruere forekomsten av ”

2.1. Problemet

Først - la oss ta en titt på Jsonmappingexception: Can Not Construct Instance Of.

Dette unntaket kastes hvis Jackson kan ikke opprette en forekomst av klassen - dette skjer hvis klassen er det abstrakt eller det er bare en grensesnitt.

I det følgende eksemplet - prøver vi å deserialisere en forekomst fra klassen dyrehage som har en eiendom dyr med abstrakt type Dyr:

offentlig klasse Zoo {offentlig Dyredyr; public Zoo () {}} abstrakt klasse Animal {public Strengnavn; public Animal () {}} klasse Cat utvider Animal {public int lives; offentlig katt () {}}

Når vi prøver å deserialisere en JSON String til Zoo instans kaster den "Jsonmappingexception: Can Not Construct Instance Of" som i følgende eksempel:

@Test (forventet = JsonMappingException.class) offentlig ugyldig givenAbstractClass_whenDeserializing_thenException () kaster IOException {String json = "{" animal ": {" name ":" lacy "}}"; ObjectMapper mapper = ny ObjectMapper (); mapper.reader (). forType (Zoo.class) .readValue (json); }

De fullt unntak er:

com.fasterxml.jackson.databind.JsonMappingException: Kan ikke konstruere forekomst av org.baeldung.jackson.exception.Animal, problem: abstrakte typer må enten kartlegges til konkrete typer, ha tilpasset deserializer, eller bli instantiert med ytterligere typeinformasjon på [Kilde: {"animal": {"name": "lacy"}}; linje: 1, kolonne: 2] (gjennom referansekjede: org.baeldung.jackson.exception.Zoo ["animal"]) på c.f.j.d.JsonMappingException.from (JsonMappingException.java:148)

2.2. Løsninger

Vi kan løse problemet med en enkel kommentar - @JsonDeserialize på den abstrakte klassen:

@JsonDeserialize (as = Cat.class) abstrakt klasse Animal {...}

Hvis vi har mer enn én undertype av abstraktklassen, bør vi vurdere å inkludere subtypeinformasjon som vist i dette innlegget: Arv med Jackson.

3. JsonMappingException: Ingen egnede konstruktører

3.1. Problemet

Nå - la oss se på det vanlige Jsonmappingexception: No Suitable Constructor funnet for type.

Dette unntaket kastes hvis Jackson får ikke tilgang til konstruktøren.

I det følgende eksemplet - klasse Bruker har ikke en standardkonstruktør:

public class User {public int id; offentlig streng navn; offentlig bruker (int id, strengnavn) {this.id = id; this.name = navn; }}

Når vi prøver å deserialisere en JSON-streng til brukeren, kastes et unntak "Jsonmappingexception: No Suitable Constructor found" - som i følgende eksempel:

@Test (forventet = JsonMappingException.class) offentlig tomrom gittNoDefaultConstructor_whenDeserializing_thenException () kaster IOException {String json = "{" id ": 1," name ":" John "}"; ObjectMapper mapper = ny ObjectMapper (); mapper.reader (). forType (User.class) .readValue (json); }

De fullt unntak er:

com.fasterxml.jackson.databind.JsonMappingException: Ingen passende konstruktører funnet for type [enkel type, klasse org.baeldung.jackson.exception.User]: kan ikke starte fra JSON-objekt (trenger å legge til / aktivere typeinformasjon?) på [ Kilde: {"id": 1, "name": "John"}; linje: 1, kolonne: 2] på c.f.j.d.JsonMappingException.from (JsonMappingException.java:148)

3.2. Løsningen

For å løse dette problemet - bare legg til en standardkonstruktør som i følgende eksempel:

public class User {public int id; offentlig streng navn; offentlig bruker () {super (); } offentlig bruker (int id, strengnavn) {this.id = id; this.name = navn; }}

Nå når vi deserialiserer - prosessen vil fungere bra:

@Test offentlig ugyldighet gittDefaultConstructor_whenDeserializing_thenCorrect () kaster IOException {String json = "{" id ": 1," name ":" John "}"; ObjectMapper mapper = ny ObjectMapper (); Brukerbruker = mapper.reader () .forType (User.class) .readValue (json); assertEquals ("John", bruker.navn); }

4. JsonMappingException: Rotnavnet samsvarer ikke med forventet

4.1. Problemet

Neste - la oss ta en titt på Jsonmappingexception: Root Name matches Not Expected.

Dette unntaket kastes hvis JSON samsvarer ikke nøyaktig med det Jackson leter etter; for eksempel kan hoved-JSON pakkes inn som i følgende eksempel:

@Test (forventet = JsonMappingException.class) offentlig ugyldig givenWrappedJsonString_whenDeserializing_thenException () kaster IOException {String json = "{" user ": {" id ": 1," name ":" John "}}"; ObjectMapper mapper = ny ObjectMapper (); mapper.enable (DeserializationFeature.UNWRAP_ROOT_VALUE); mapper.reader (). forType (User.class) .readValue (json); }

De fullt unntak er:

com.fasterxml.jackson.databind.JsonMappingException: Rotnavnet 'bruker' samsvarer ikke med forventet ('Bruker') for typen [enkel type, klasse org.baeldung.jackson.dtos.User] på [Kilde: {"bruker": {"id": 1, "name": "John"}}; linje: 1, kolonne: 2] på c.f.j.d.JsonMappingException.from (JsonMappingException.java:148) 

4.2. Løsningen

Vi kan løse dette problemet ved hjelp av kommentaren @JsonRootName - som i følgende eksempel:

@JsonRootName (value = "user") offentlig klasse UserWithRoot {public int id; offentlig streng navn; }

Når vi prøver å deserialisere den innpakket JSON - fungerer det riktig:

@Test offentlig ugyldighet givenWrappedJsonStringAndConfigureClass_whenDeserializing_thenCorrect () kaster IOException {String json = "{" user ": {" id ": 1," name ":" John "}}"; ObjectMapper mapper = ny ObjectMapper (); mapper.enable (DeserializationFeature.UNWRAP_ROOT_VALUE); UserWithRoot user = mapper.reader () .forType (UserWithRoot.class) .readValue (json); assertEquals ("John", bruker.navn); }

5. JsonMappingException: Ingen serialiser funnet for klasse

5.1. Problemet

La oss ta en titt på Jsonmappingexception: No Serializer Found for Class.

Dette unntaket blir kastet hvis du prøver å serieiser en forekomst mens egenskapene og deres getters er private.

I det følgende eksemplet - prøver vi å serieisere en “UserWithPrivateFields“:

offentlig klasse UserWithPrivateFields {int id; Strengnavn; }

Når vi prøver å serieisere en forekomst av “UserWithPrivateFields”- et unntak“ Jsonmappingexception: No Serializer Found for Class ”kastes som i følgende eksempel:

@Test (forventet = JsonMappingException.class) offentlig ugyldig givenClassWithPrivateFields_whenSerializing_thenException () kaster IOException {UserWithPrivateFields bruker = ny UserWithPrivateFields (1, "John"); ObjectMapper mapper = ny ObjectMapper (); mapper.writer (). writeValueAsString (bruker); }

Hele unntaket er:

com.fasterxml.jackson.databind.JsonMappingException: Ingen serializer funnet for klasse org.baeldung.jackson.exception.UserWithPrivateFields og ingen egenskaper oppdaget for å lage BeanSerializer (for å unngå unntak, deaktiver SerializationFeature.FAIL_ON_EMPTY_BEANS)) på cfjdser.Simplizer failForEmpty (UnknownSerializer.java:59)

5.2. Løsningen

Vi kan løse dette problemet ved å konfigurere ObjectMapper synlighet - som i følgende eksempel:

@Test offentlig ugyldighet givenClassWithPrivateFields_whenConfigureSerializing_thenCorrect () kaster IOException {UserWithPrivateFields bruker = ny UserWithPrivateFields (1, "John"); ObjectMapper mapper = ny ObjectMapper (); mapper.setVisibility (PropertyAccessor.FIELD, Visibility.ANY); Strengresultat = mapper.writer (). WriteValueAsString (bruker); assertThat (resultat, inneholderString ("John")); }

Eller ved å bruke kommentaren @JsonAutoDetect - som i følgende eksempel:

@JsonAutoDetect (fieldVisibility = Visibility.ANY) offentlig klasse UserWithPrivateFields {...}

Selvfølgelig, hvis vi har muligheten til å endre kilden til klassen, kan vi også legge til getters som Jackson kan bruke.

6. JsonMappingException: Kan ikke deserialisere forekomsten av

6.1. Problemet

Neste - la oss ta en titt på Jsonmappingexception: Can Not Deserialize Instance Of.

Dette unntaket kastes hvis feil type brukes mens deserialisering.

I det følgende eksemplet - prøver vi å deserialisere en Liste av Bruker:

@Test (forventet = JsonMappingException.class) offentlig ugyldig gittJsonOfArray_whenDeserializing_thenException () kaster JsonProcessingException, IOException {String json = "[{" id ": 1," name ":" John "}, {" id ": 2," name " : "Adam"}] "; ObjectMapper mapper = ny ObjectMapper (); mapper.reader (). forType (User.class) .readValue (json); }

De fullt unntak er:

com.fasterxml.jackson.databind.JsonMappingException: Kan ikke deserialisere forekomsten av org.baeldung.jackson.dtos. Bruker av START_ARRAY-token på [Kilde: [{"id": 1, "name": "John"}, { "id": 2, "name": "Adam"}]; linje: 1, kolonne: 1] på c.f.j.d.JsonMappingException.from (JsonMappingException.java:148)

6.2. Løsningen

Vi kan løse dette problemet ved å endre typen fra Bruker til Liste - som i følgende eksempel:

@Test offentlig ugyldighet gittJsonOfArray_whenDeserializing_thenCorrect () kaster JsonProcessingException, IOException {String json = "[{" id ": 1," name ":" John "}, {" id ": 2," name ":" Adam "}]" ; ObjectMapper mapper = ny ObjectMapper (); Liste brukere = mapper.reader () .forType (ny TypeReference() {}) .readValue (json); assertEquals (2, users.size ()); }

7. UnrecognizedPropertyException

7.1. Problemet

Nå - la oss se UnrecognizedPropertyException.

Dette unntaket blir kastet hvis det er et ukjent eiendom i JSON Streng mens deserialisering.

I det følgende eksemplet - prøver vi å deserialisere en JSON-streng med ekstra eiendom “sjekket“:

@Test (forventet = UnrecognizedPropertyException.class) offentlig ugyldig gittJsonStringWithExtra_whenDeserializing_thenException () kaster IOException {String json = "{" id ": 1," name ":" John "," checked ": true}"; ObjectMapper mapper = ny ObjectMapper (); mapper.reader (). forType (User.class) .readValue (json); }

De fullt unntak er:

com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Ukjent felt "avkrysset" (klasse org.baeldung.jackson.dtos.User), ikke merket som uvitende (2 kjente egenskaper: "id", "name"]) på [ Kilde: {"id": 1, "name": "John", "checked": true}; linje: 1, kolonne: 38] (gjennom referansekjede: org.baeldung.jackson.dtos.User ["avkrysset"]) på c.f.j.d.exc.UnrecognizedPropertyException.from (UnrecognizedPropertyException.java:51)

7.2. Løsningen

Vi kan løse dette problemet ved å konfigurere ObjectMapper - som i følgende eksempel:

@Test offentlig ugyldighet gittJsonStringWithExtra_whenConfigureDeserializing_thenCorrect () kaster IOException {String json = "{" id ": 1," name ":" John "," checked ": true}"; ObjectMapper mapper = ny ObjectMapper (); mapper.disable (DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); Brukerbruker = mapper.reader (). ForType (User.class) .readValue (json); assertEquals ("John", bruker.navn); }

Eller vi kan bruke kommentaren @JsonIgnoreProperties:

@JsonIgnoreProperties (ignoreUnknown = true) bruker i offentlig klasse {...}

8. JsonParseException: Uventet karakter (”'(kode 39))

8.1. Problemet

Neste - la oss diskutere JsonParseException: Uventet tegn (”'(kode 39)).

Dette unntaket kastes hvis JSON-strengen som skal deserialiseres inneholder enkelt anførselstegn i stedet for doble anførselstegn.

I det følgende eksemplet - prøver vi å deserialisere en JSON-streng som inneholder enkle anførselstegn:

@Test (forventet = JsonParseException.class) offentlig ugyldig givenStringWithSingleQuotes_whenDeserializing_thenException () kaster JsonProcessingException, IOException {String json = "{'id': 1, 'name': 'John'}"; ObjectMapper mapper = ny ObjectMapper (); mapper.reader () .forType (User.class) .readValue (json); }

De fullt unntak er:

com.fasterxml.jackson.core.JsonParseException: Uventet tegn ('' '(kode 39)): forventet dobbelt anførselstegn for å starte feltnavnet ved [Kilde: {' id ': 1,' name ':' John '} ; linje: 1, kolonne: 3] på c.f.j.core.JsonParser._constructError (JsonParser.java:1419)

8.2. Løsningen

Vi kan løse dette ved å konfigurere ObjectMapper for å tillate enkelt tilbud:

@Test offentlig ugyldig gittStringWithSingleQuotes_whenConfigureDeserializing_thenCorrect () kaster JsonProcessingException, IOException {String json = "{'id': 1, 'name': 'John'}"; JsonFactory fabrikk = ny JsonFactory (); factory.enable (JsonParser.Feature.ALLOW_SINGLE_QUOTES); ObjectMapper mapper = ny ObjectMapper (fabrikk); Brukerbruker = mapper.reader (). ForType (User.class) .readValue (json); assertEquals ("John", bruker.navn); }

9. Jackson NoSuchMethodError

Til slutt - la oss raskt diskutere Jackson "No such method" -feil.

Når java.lang.NoSuchMethodError Unntak blir kastet, det er vanligvis fordi du har flere (og inkompatible) versjoner av Jackson-krukker på klassestien din.

De fullt unntak er:

java.lang.NoSuchMethodError: com.fasterxml.jackson.core.JsonParser.getValueAsString () Ljava / lang / String; på c.f.j.d.deser.std.StringDeserializer.deserialize (StringDeserializer.java:24)

10. Konklusjon

I denne artikkelen gjorde vi et dypdykk i de vanligste Jackson-problemene - unntak og feil, ser på de potensielle årsakene og på løsningene for hver enkelt.

Implementeringen av alle disse eksemplene og kodebiter finner du på Github - 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