Jacksonove iznimke - problemi i rješenja
1. Pregled
U ovom uputstvu ćemo prijeći najčešće Jackson iznimke - the JsonMappingException i NeprepoznatiPropertyException.
Napokon - ukratko ćemo razgovarati o Jacksonu bez takvih pogrešaka u metodi.
2. “JsonMappingException: Ne mogu konstruirati instancu ”
2.1. Problem
Prvo - pogledajmo Jsonmappingexception: Can't Construct Instance Of.
Ova se iznimka baca ako Jackson ne može stvoriti primjerak klase - to se događa ako je nastava sažetak ili je samo sučelje.
U sljedećem primjeru - pokušavamo deserializirati instancu iz klase Zoološki vrt koja ima svojstvo životinja s sažetak tip Životinja:
javni razred Zoo {javna Životinjska životinja; javni zoološki vrt () {}} sažetak klase životinja {javni naziv niza; javni Animal () {}} klasa Cat produžuje Animal {javni int život; javna mačka () {}}
Kada pokušamo deserializirati JSON Niz instanci Zoo-a baca “Jsonmappingexception: Can't Construct Instance Of” kao u sljedećem primjeru:
@Test (očekuje se = JsonMappingException.class) javna praznina givenAbstractClass_whenDeserializing_thenException () baca IOException {String json = "{" animal ": {" name ":" lacy "}}"; Mapa ObjectMapper = novi ObjectMapper (); mapper.reader (). forType (Zoo.class) .readValue (json); }
The puna iznimka je:
com.fasterxml.jackson.databind.JsonMappingException: Ne može se stvoriti instanca org.baeldung.jackson.exception.Animal, problem: apstraktni tipovi moraju biti mapirani u konkretne tipove, imati prilagođeni deserijalizator ili biti instancirani dodatnim informacijama o tipu [Izvor: {"životinja": {"ime": "čipkasto"}}; redak: 1, stupac: 2] (kroz referentni lanac: org.baeldung.jackson.exception.Zoo ["životinja"]) na c.f.j.d.JsonMappingException.from (JsonMappingException.java:148)
2.2. Rješenja
Problem možemo riješiti jednostavnom bilješkom - @JsonDeserialize na apstraktnom satu:
@JsonDeserialize (as = Cat.class) sažetak klase Životinja {...}
Ako imamo više od jedne podvrste apstraktne klase, trebali bismo razmotriti uključivanje informacija o podvrsti kao što je prikazano u ovom postu: Nasljeđivanje s Jacksonom.
3. JsonMappingException: Nema prikladnog konstruktora
3.1. Problem
Sada - pogledajmo uobičajeni Jsonmappingexception: Nema prikladnog konstruktora pronađeno za tip.
Ova se iznimka baca ako Jackson ne može pristupiti konstruktoru.
U sljedećem primjeru - klasa Korisnik nema zadani konstruktor:
javni razred korisnika {javni int id; naziv javnog niza; javni korisnik (int id, naziv niza) {this.id = id; this.name = ime; }}
Kada pokušavamo deserializirati JSON niz za korisnika, izbacuje se izuzetak "Jsonmappingexception: Nije pronađen odgovarajući konstruktor" - kao u sljedećem primjeru:
@Test (očekuje se = JsonMappingException.class) javna praznina givenNoDefaultConstructor_whenDeserializing_thenException () baca IOException {String json = "{" id ": 1," name ":" John "}"; Mapa ObjectMapper = novi ObjectMapper (); mapper.reader (). forType (User.class) .readValue (json); }
The puna iznimka je:
com.fasterxml.jackson.databind.JsonMappingException: Nije pronađen odgovarajući konstruktor za tip [jednostavan tip, klasa org.baeldung.jackson.exception.User]: nije moguće instanciranje iz JSON objekta (trebate dodati / omogućiti informacije o tipu?) na Izvor: {"id": 1, "name": "John"}; redak: 1, stupac: 2] na c.f.j.d.JsonMappingException.from (JsonMappingException.java:148)
3.2. Rješenje
Da biste riješili ovaj problem - samo dodajte zadani konstruktor kao u sljedećem primjeru:
javni razred korisnika {javni int id; naziv javnog niza; javni korisnik () {super (); } javni korisnik (int id, naziv niza) {this.id = id; this.name = ime; }}
Sada kada desezeriziramo - postupak će raditi sasvim u redu:
@Test javna praznina givenDefaultConstructor_whenDeserializing_thenCorrect () baca IOException {String json = "{" id ": 1," name ":" John "}"; Mapa ObjectMapper = novi ObjectMapper (); Korisnik korisnik = mapper.reader () .forType (User.class) .readValue (json); assertEquals ("John", korisničko ime); }
4. JsonMappingException: Ime korijena se ne podudara s očekivanim
4.1. Problem
Dalje - pogledajmo Jsonmappingexception: Ime korijena se ne podudara s očekivanim.
Ova se iznimka baca ako JSON se ne podudara točno s onim što Jackson traži; na primjer, glavni JSON mogao bi biti omotan kao u sljedećem primjeru:
@Test (očekuje se = JsonMappingException.class) javna praznina givenWrappedJsonString_whenDeserializing_thenException () baca IOException {String json = "{" user ": {" id ": 1," name ":" John "}}"; Mapa ObjectMapper = novi ObjectMapper (); mapper.enable (DeserializationFeature.UNWRAP_ROOT_VALUE); mapper.reader (). forType (User.class) .readValue (json); }
The puna iznimka je:
com.fasterxml.jackson.databind.JsonMappingException: Ime korijena 'user' ne podudara se s očekivanim ('User') za tip [simple type, class org.baeldung.jackson.dtos.User] na [Source: {"user": {"id": 1, "name": "Ivan"}}; redak: 1, stupac: 2] na c.f.j.d.JsonMappingException.from (JsonMappingException.java:148)
4.2. Rješenje
Ovaj problem možemo riješiti pomoću bilješke @JsonRootName - kao u sljedećem primjeru:
@JsonRootName (value = "user") javna klasa UserWithRoot {javni int id; naziv javnog niza; }
Kada pokušamo deserializirati zamotani JSON - to ispravno radi:
@Test javna praznina givenWrappedJsonStringAndConfigureClass_whenDeserializing_thenCorrect () baca IOException {String json = "{" user ": {" id ": 1," name ":" John "}}"; Mapa ObjectMapper = novi ObjectMapper (); mapper.enable (DeserializationFeature.UNWRAP_ROOT_VALUE); UserWithRoot user = mapper.reader () .forType (UserWithRoot.class) .readValue (json); assertEquals ("John", korisničko ime); }
5. JsonMappingException: Nije pronađen serijalizator za klasu
5.1. Problem
Sada - pogledajmo Jsonmappingexception: Nije pronađen serilizator za klasu.
Ova se iznimka baca ako pokušate serializirajte instancu dok su njena svojstva i njihovi dohvatači privatni.
U sljedećem primjeru - pokušavamo serializirati "UserWithPrivateFields“:
javna klasa UserWithPrivateFields {int id; Naziv niza; }
Kada pokušamo serializirati instancu „UserWithPrivateFields"- dodana je iznimka" Jsonmappingexception: Nije pronađen serilizator za klasu "kao u sljedećem primjeru:
@Test (očekuje se = JsonMappingException.class) javna praznina givenClassWithPrivateFields_whenSerializing_thenException () baca IOException {UserWithPrivateFields user = new UserWithPrivateFields (1, "John"); Mapa ObjectMapper = novi ObjectMapper (); mapper.writer (). writeValueAsString (korisnik); }
Potpuna iznimka je:
com.fasterxml.jackson.databind.JsonMappingException: Nije pronađen serializator za klasu org.baeldung.jackson.exception.UserWithPrivateFields i nisu otkrivena svojstva za stvaranje BeanSerializer-a (da biste izbjegli izuzeće, onemogućite SerializationFeature.FAIL_ON_EMPTY_BEANSUERBEANSERP. failForEmpty (UnknownSerializer.java:59)
5.2. Rješenje
Taj problem možemo riješiti konfiguriranjem datoteke ObjectMapper vidljivost - kao u sljedećem primjeru:
@Test javna praznina givenClassWithPrivateFields_whenConfigureSerializing_thenCorrect () baca IOException {UserWithPrivateFields user = new UserWithPrivateFields (1, "John"); Mapa ObjectMapper = novi ObjectMapper (); mapper.setVisibility (PropertyAccessor.FIELD, Visibility.ANY); Rezultat niza = mapper.writer (). WriteValueAsString (korisnik); assertThat (rezultat, sadržiString ("Ivan")); }
Ili pomoću bilješke @JsonAutoDetect - kao u sljedećem primjeru:
@JsonAutoDetect (fieldVisibility = Visibility.ANY) javna klasa UserWithPrivateFields {...}
Naravno, ako imamo mogućnost modificiranja izvora klase, možemo dodati i gettere koje će Jackson koristiti.
6. JsonMappingException: Ne mogu deserijalizirati instancu
6.1. Problem
Dalje - pogledajmo Jsonmappingexception: Nije moguće deserijalizirati instancu.
Ova se iznimka baca ako koristi se pogrešan tip dok se deserializira.
U sljedećem primjeru - pokušavamo deserializirati a Popis od Korisnik:
@Test (očekuje se = JsonMappingException.class) javna praznina givenJsonOfArray_whenDeserializing_thenException () baca JsonProcessingException, IOException {String json = "[{" id ": 1," name ":" John "}, {" id ": 2" id ": 2" :"Adam"}]"; Mapa ObjectMapper = novi ObjectMapper (); mapper.reader (). forType (User.class) .readValue (json); }
The puna iznimka je:
com.fasterxml.jackson.databind.JsonMappingException: Nije moguće deserializirati instancu org.baeldung.jackson.dtos.Korisnik iz START_ARRAY tokena na [Izvor: [{"id": 1, "name": "John"}, { "id": 2, "name": "Adam"}]; redak: 1, stupac: 1] na c.f.j.d.JsonMappingException.from (JsonMappingException.java:148)
6.2. Rješenje
Taj problem možemo riješiti promjenom tipa iz Korisnik do Popis - kao u sljedećem primjeru:
@Test public void givenJsonOfArray_whenDeserializing_thenCorrect () baca JsonProcessingException, IOException {String json = "[{" id ": 1," name ":" John "}, {" id ": 2," name ":" Adam "}]" " ; Mapa ObjectMapper = novi ObjectMapper (); Popis korisnika = mapper.reader () .forType (novi TypeReference() {}) .readValue (json); assertEquals (2, users.size ()); }
7. NeprepoznatiPropertyException
7.1. Problem
Sad - da vidimo NeprepoznatiPropertyException.
Ova se iznimka baca ako postoji nepoznato svojstvo u JSON-u String tijekom deserializacije.
U sljedećem primjeru - pokušavamo deserializirati JSON niz s dodatnim svojstvom “provjereno“:
@Test (očekuje se = NeprepoznatoPropertyException.class) javna praznina givenJsonStringWithExtra_whenDeserializing_thenException () baca IOException {String json = "{" id ": 1," name ":" John "," checked ": true}"; Mapa ObjectMapper = novi ObjectMapper (); mapper.reader (). forType (User.class) .readValue (json); }
The puna iznimka je:
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Neprepoznato polje "provjereno" (klasa org.baeldung.jackson.dtos.User), nije označeno kao zanemarivo (2 poznata svojstva: "id", "name"]) na [ Izvor: {"id": 1, "name": "John", "check": true}; redak: 1, stupac: 38] (kroz referentni lanac: org.baeldung.jackson.dtos.User ["provjereno"]) na c.f.j.d.exc.UnrecognizedPropertyException.from (UnrecognizedPropertyException.java:51)
7.2. Rješenje
Taj problem možemo riješiti konfiguriranjem datoteke ObjectMapper - kao u sljedećem primjeru:
@Test javna praznina givenJsonStringWithExtra_whenConfigureDeserializing_thenCorrect () baca IOException {String json = "{" id ": 1," name ":" John "," checked ": true}"; Mapa ObjectMapper = novi ObjectMapper (); mapper.disable (DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); Korisnik korisnik = mapper.reader (). ForType (User.class) .readValue (json); assertEquals ("John", korisničko ime); }
Ili se možemo poslužiti napomenom @JsonIgnoreProperties:
@JsonIgnoreProperties (ignoreUnknown = true) korisnik javne klase {...}
8. JsonParseException: Neočekivani znak ("'(kod 39))
8.1. Problem
Dalje - razgovarajmo JsonParseException: Neočekivani znak (”'(kod 39)).
Ova se iznimka baca ako JSON-ov niz koji će se deserijalizirati sadrži pojedinačne navodnike umjesto dvostrukih navodnika.
U sljedećem primjeru - pokušavamo deserializirati JSON niz koji sadrži pojedinačne navodnike:
@Test (očekuje se = JsonParseException.class) javna praznina givenStringWithSingleQuotes_whenDeserializing_thenException () baca JsonProcessingException, IOException {String json = "{'id': 1, 'name': 'John'}"; Mapa ObjectMapper = novi ObjectMapper (); mapper.reader () .forType (User.class) .readValue (json); }
The puna iznimka je:
com.fasterxml.jackson.core.JsonParseException: Neočekivani znak ('' '(kod 39)): očekivao je dvostruki navodnik za početak imena polja na [Izvor: {' id ': 1,' name ':' John '} ; redak: 1, stupac: 3] na c.f.j.core.JsonParser._constructError (JsonParser.java:1419)
8.2. Rješenje
To možemo riješiti konfiguriranjem ObjectMapper dopustiti pojedinačne citate:
@Test javna praznina givenStringWithSingleQuotes_whenConfigureDeserializing_thenCorrect () baca JsonProcessingException, IOException {String json = "{'id': 1, 'name': 'John'}"; Tvornica JsonFactory = nova JsonFactory (); factory.enable (JsonParser.Feature.ALLOW_SINGLE_QUOTES); ObjectMapper mapper = novi ObjectMapper (tvornički); Korisnik korisnik = mapper.reader (). ForType (User.class) .readValue (json); assertEquals ("John", korisničko ime); }
9. Jackson NoSuchMethodError
Napokon - razgovarajmo brzo o Jacksonovim pogreškama "Nema takve metode".
Kada java.lang.NoSuchMethodError Iznimka se izbacuje, to je obično zato što na putu do razreda imate više (i nekompatibilnih) verzija Jackson staklenki.
The puna iznimka je:
java.lang.NoSuchMethodError: com.fasterxml.jackson.core.JsonParser.getValueAsString () Ljava / lang / String; na c.f.j.d.deser.std.StringDeserializer.deserialize (StringDeserializer.java:24)
10. Zaključak
U ovom smo članku duboko zaronili najčešći Jacksonovi problemi - iznimke i pogreške, gledajući potencijalne uzroke i rješenja za svaki od njih.
Implementacija svih ovih primjera i isječaka koda može se naći na Githubu - ovo je projekt zasnovan na Mavenu, pa bi ga trebalo biti lako uvesti i pokrenuti kakav jest.