Jackson Undtagelser - Problemer og løsninger
1. Oversigt
I denne vejledning går vi over de mest almindelige Jackson-undtagelser - det JsonMappingException og UnrecognisedPropertyException.
Endelig - vi vil kort diskutere Jackson ingen sådanne metodefejl.
2. “JsonMappingException: Kan ikke konstruere forekomsten af ”
2.1. Problemet
Først - lad os tage et kig på Jsonmappingexception: Can not Construct Instance Of.
Denne undtagelse kastes, hvis Jackson kan ikke oprette en forekomst af klassen - dette sker, hvis klassen er det abstrakt eller det er bare en interface.
I det følgende eksempel prøver vi at deserialisere en forekomst fra klassen Zoo som har en ejendom dyr med abstrakt type Dyr:
offentlig klasse Zoo {offentligt dyr; public Zoo () {}} abstrakt klasse Animal {public String name; public Animal () {}} klasse Cat udvider Animal {public int lives; offentlig kat () {}}
Når vi prøver at deserialisere en JSON Snor til Zoo-instans kaster det “Jsonmappingexception: Can not Construct Instance Of” som i følgende eksempel:
@Test (forventet = JsonMappingException.class) offentlig ugyldighed givenAbstractClass_whenDeserializing_thenException () kaster IOException {String json = "{" animal ": {" name ":" lacy "}}"; ObjectMapper-kortlægger = ny ObjectMapper (); mapper.reader (). forType (Zoo.class) .readValue (json); }
Det fuld undtagelse er:
com.fasterxml.jackson.databind.JsonMappingException: Kan ikke konstruere forekomst af org.baeldung.jackson.exception.Animal, problem: abstrakte typer skal enten kortlægges til konkrete typer, har brugerdefineret deserializer eller instantieres med yderligere typeoplysninger på [Kilde: {"animal": {"name": "lacy"}}; linje: 1, kolonne: 2] (gennem referencekæde: 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 simpel kommentar - @JsonDeserialize på den abstrakte klasse:
@JsonDeserialize (som = Cat.class) abstrakt klasse Animal {...}
Hvis vi har mere end en undertype af den abstrakte klasse, bør vi overveje at inkludere subtypeoplysninger som vist i dette indlæg: Arv med Jackson.
3. JsonMappingException: Ingen egnede konstruktører
3.1. Problemet
Lad os nu se på den almindelige Jsonmappingexception: Ingen egnet konstruktør fundet for type.
Denne undtagelse kastes, hvis Jackson har ikke adgang til konstruktøren.
I det følgende eksempel - klasse Bruger har ikke en standardkonstruktør:
public class User {public int id; offentligt strengnavn; offentlig bruger (int id, strengnavn) {this.id = id; dette.navn = navn; }}
Når vi forsøger at deserialisere en JSON-streng til bruger, kastes en undtagelse "Jsonmappingexception: No Suitable Constructor found" - som i følgende eksempel:
@Test (forventet = JsonMappingException.class) offentlig ugyldighed givenNoDefaultConstructor_whenDeserializing_thenException () kaster IOException {String json = "{" id ": 1," name ":" John "}"; ObjectMapper-kortlægger = ny ObjectMapper (); mapper.reader (). forType (User.class) .readValue (json); }
Det fuld undtagelse er:
com.fasterxml.jackson.databind.JsonMappingException: Ingen passende konstruktør fundet til type [enkel type, klasse org.baeldung.jackson.exception.User]: kan ikke instantiere fra JSON-objekt (har brug for at tilføje / aktivere typeoplysninger?) 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 at løse dette problem - tilføj bare en standardkonstruktør som i følgende eksempel:
public class User {public int id; offentligt strengnavn; offentlig bruger () {super (); } offentlig bruger (int id, strengnavn) {this.id = id; dette.navn = navn; }}
Nu når vi deserialiserer - processen fungerer fint:
@Test offentlig ugyldighed givenDefaultConstructor_whenDeserializing_thenCorrect () kaster IOException {String json = "{" id ": 1," name ":" John "}"; ObjectMapper-kortlægger = ny ObjectMapper (); Brugerbruger = mapper.reader () .forType (User.class) .readValue (json); assertEquals ("John", bruger.navn); }
4. JsonMappingException: Rodnavn stemmer ikke overens forventet
4.1. Problemet
Dernæst - lad os se på Jsonmappingexception: Root Name matcher ikke forventet.
Denne undtagelse kastes, hvis JSON matcher ikke nøjagtigt, hvad Jackson leder efter; for eksempel kunne hoved-JSON pakkes ind som i følgende eksempel:
@Test (forventet = JsonMappingException.class) offentlig ugyldighed givenWrappedJsonString_whenDeserializing_thenException () kaster IOException {String json = "{" bruger ": {" id ": 1," navn ":" John "}}"; ObjectMapper-kortlægger = ny ObjectMapper (); mapper.enable (DeserializationFeature.UNWRAP_ROOT_VALUE); mapper.reader (). forType (User.class) .readValue (json); }
Det fuld undtagelse er:
com.fasterxml.jackson.databind.JsonMappingException: rodnavnet 'bruger' matcher ikke forventet ('bruger') for typen [enkel type, klasse org.baeldung.jackson.dtos.User] på [Kilde: {"bruger": {"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 problem ved hjælp af kommentaren @JsonRootName - som i følgende eksempel:
@JsonRootName (værdi = "bruger") offentlig klasse UserWithRoot {public int id; offentligt strengnavn; }
Når vi forsøger at deserialisere den indpakkede JSON - fungerer det korrekt:
@Test offentlig ugyldighed givenWrappedJsonStringAndConfigureClass_whenDeserializing_thenCorrect () kaster IOException {String json = "{" bruger ": {" id ": 1," name ":" John "}}"; ObjectMapper-kortlægger = ny ObjectMapper (); mapper.enable (DeserializationFeature.UNWRAP_ROOT_VALUE); UserWithRoot-bruger = mapper.reader (). ForType (UserWithRoot.class) .readValue (json); assertEquals ("John", bruger.navn); }
5. JsonMappingException: Ingen Serializer fundet til klasse
5.1. Problemet
Lad os nu se på Jsonmappingexception: Ingen serializer fundet til klasse.
Denne undtagelse kastes, hvis du prøver serialisere en forekomst, mens dens egenskaber og deres getters er private.
I det følgende eksempel - vi forsøger at serieisere en “UserWithPrivateFields“:
offentlig klasse UserWithPrivateFields {int id; Strengnavn; }
Når vi forsøger at serieisere en forekomst af “UserWithPrivateFields”- en undtagelse“ Jsonmappingexception: No Serializer Found for Class ”kastes som i følgende eksempel:
@Test (forventet = JsonMappingException.class) offentlig ugyldighed givenClassWithPrivateFields_whenSerializing_thenException () kaster IOException {UserWithPrivateFields bruger = ny UserWithPrivateFields (1, "John"); ObjectMapper-kortlægger = ny ObjectMapper (); mapper.writer (). writeValueAsString (bruger); }
Den fulde undtagelse er:
com.fasterxml.jackson.databind.JsonMappingException: Ingen serializer fundet til klasse org.baeldung.jackson.exception.UserWithPrivateFields og ingen egenskaber opdaget til at oprette BeanSerializer (for at undgå undtagelse skal du deaktivere SerializationFeature.FAIL_ON_EMPTY_BEANS)) ved cfjdser.Simplizer. failForEmpty (UnknownSerializer.java:59)
5.2. Løsningen
Vi kan løse dette problem ved at konfigurere ObjectMapper synlighed - som i følgende eksempel:
@Test offentlig ugyldighed givenClassWithPrivateFields_whenConfigureSerializing_thenCorrect () kaster IOException {UserWithPrivateFields bruger = ny UserWithPrivateFields (1, "John"); ObjectMapper-kortlægger = ny ObjectMapper (); mapper.setVisibility (PropertyAccessor.FIELD, Visibility.ANY); Strengresultat = mapper.writer (). WriteValueAsString (bruger); assertThat (resultat, indeholderString ("John")); }
Eller ved hjælp af kommentaren @JsonAutoDetect - som i følgende eksempel:
@JsonAutoDetect (fieldVisibility = Visibility.ANY) offentlig klasse UserWithPrivateFields {...}
Selvfølgelig, hvis vi har mulighed for at ændre klassens kilde, kan vi også tilføje i getters, som Jackson kan bruge.
6. JsonMappingException: Kan ikke deserialisere forekomsten af
6.1. Problemet
Dernæst - lad os se på Jsonmappingexception: Can not Deserialize Instance Of.
Denne undtagelse kastes, hvis den forkerte type bruges mens deserialisering.
I det følgende eksempel prøver vi at deserialisere en Liste af Bruger:
@Test (forventet = JsonMappingException.class) offentlig ugyldighed givetJsonOfArray_whenDeserializing_thenException () kaster JsonProcessingException, IOException {String json = "[{" id ": 1," name ":" John "}, {" id ": 2," name " : "Adam"}] "; ObjectMapper-kortlægger = ny ObjectMapper (); mapper.reader (). forType (User.class) .readValue (json); }
Det fuld undtagelse er:
com.fasterxml.jackson.databind.JsonMappingException: Kan ikke deserialisere forekomst af org.baeldung.jackson.dtos.User ud af START_ARRAY-token ved [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 problem ved at ændre typen fra Bruger til Liste - som i følgende eksempel:
@Test offentligt ugyldigt givetJsonOfArray_whenDeserializing_thenCorrect () kaster JsonProcessingException, IOException {String json = "[{" id ": 1," name ":" John "}, {" id ": 2," name ":" Adam "}]" ; ObjectMapper-kortlægger = ny ObjectMapper (); Liste brugere = mapper.reader () .forType (ny TypeReference() {}) .readValue (json); assertEquals (2, users.size ()); }
7. UnrecognisedPropertyException
7.1. Problemet
Lad os nu se UnrecognisedPropertyException.
Denne undtagelse kastes, hvis der er en ukendt ejendom i JSON Streng under deserialisering.
I det følgende eksempel - forsøger vi at deserialisere en JSON-streng med ekstra egenskab “afkrydset“:
@Test (forventet = UnrecognizedPropertyException.class) offentlig ugyldighed givenJsonStringWithExtra_whenDeserializing_thenException () kaster IOException {String json = "{" id ": 1," name ":" John "," kontrolleret ": sand}"; ObjectMapper-kortlægger = ny ObjectMapper (); mapper.reader (). forType (User.class) .readValue (json); }
Det fuld undtagelse er:
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Ikke-genkendt felt "markeret" (klasse org.baeldung.jackson.dtos.User), ikke markeret som uvidende (2 kendte egenskaber: "id", "name"]) ved [ Kilde: {"id": 1, "name": "John", "markeret": true}; linje: 1, kolonne: 38] (gennem referencekæde: org.baeldung.jackson.dtos.User ["markeret"]) ved c.f.j.d.exc.UnrecognizedPropertyException.from (UnrecognizedPropertyException.java:51)
7.2. Løsningen
Vi kan løse dette problem ved at konfigurere ObjectMapper - som i følgende eksempel:
@Test offentlig ugyldighed givetJsonStringWithExtra_whenConfigureDeserializing_thenCorrect () kaster IOException {String json = "{" id ": 1," name ":" John "," checked ": true}"; ObjectMapper-kortlægger = ny ObjectMapper (); mapper.disable (DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); Brugerbruger = mapper.reader (). ForType (User.class) .readValue (json); assertEquals ("John", bruger.navn); }
Eller vi kan bruge kommentaren @JsonIgnoreProperties:
@JsonIgnoreProperties (ignoreUnknown = true) bruger i offentlig klasse {...}
8. JsonParseException: Uventet tegn (”'(kode 39))
8.1. Problemet
Næste - lad os diskutere JsonParseException: Uventet tegn (”'(kode 39)).
Denne undtagelse kastes, hvis JSON-strengen, der skal deserialiseres, indeholder enkelt anførselstegn i stedet for dobbelt tilbud.
I det følgende eksempel - forsøger vi at deserialisere en JSON-streng, der indeholder enkelt anførselstegn:
@Test (forventet = JsonParseException.class) offentlig ugyldighed givenStringWithSingleQuotes_whenDeserializing_thenException () kaster JsonProcessingException, IOException {String json = "{'id': 1, 'name': 'John'}"; ObjectMapper-kortlægger = ny ObjectMapper (); mapper.reader () .forType (User.class) .readValue (json); }
Det fuld undtagelse er:
com.fasterxml.jackson.core.JsonParseException: Uventet tegn ('' '(kode 39)): forventede, at dobbelt citat skulle starte feltnavn ved [Kilde: {' id ': 1,' name ':' John '} ; linje: 1, kolonne: 3] ved c.f.j.core.JsonParser._constructError (JsonParser.java:1419)
8.2. Løsningen
Vi kan løse dette ved at konfigurere ObjectMapper at tillade enkelt tilbud:
@Test offentlig ugyldighed givenStringWithSingleQuotes_whenConfigureDeserializing_thenCorrect () kaster JsonProcessingException, IOException {String json = "{'id': 1, 'name': 'John'}"; JsonFactory fabrik = ny JsonFactory (); factory.enable (JsonParser.Feature.ALLOW_SINGLE_QUOTES); ObjectMapper mapper = ny ObjectMapper (fabrik); Brugerbruger = mapper.reader (). ForType (User.class) .readValue (json); assertEquals ("John", bruger.navn); }
9. Jackson NoSuchMethodError
Endelig - lad os hurtigt diskutere Jackson "Ingen sådan metode" -fejl.
Hvornår java.lang.NoSuchMethodError Undtagelse kastes, det skyldes normalt, at du har flere (og inkompatible) versioner af Jackson-krukker på din klassesti.
Det fuld undtagelse 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. Konklusion
I denne artikel dykkede vi dybt ind de mest almindelige Jackson-problemer - undtagelser og fejl, ser på de potentielle årsager og løsningerne for hver enkelt.
Implementeringen af alle disse eksempler og kodestykker kan findes på Github - dette er et Maven-baseret projekt, så det skal være let at importere og køre som det er.