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.