Jacksonove výnimky - problémy a riešenia
1. Prehľad
V tomto návode si prejdeme najbežnejšie Jacksonove výnimky - the JsonMappingException a UnrecognizedPropertyException.
Na záver - krátko hovoríme o Jacksonovi, že nedochádza k takýmto chybám metód.
2. “JsonMappingException: Nie je možné vytvoriť inštanciu “
2.1. Problém
Po prvé - poďme sa pozrieť na výnimku Jsonmapping: Can not Construct Instance Of.
Táto výnimka je vyvolaná, ak Jackson nemôže vytvoriť inštanciu triedy - toto sa stane, ak je trieda abstraktné alebo je to len rozhranie.
V nasledujúcom príklade sa pokúsime deserializovať inštanciu z triedy Zoo ktorá má nehnuteľnosť zviera s abstraktné typu Zviera:
verejná trieda Zoo {verejné Zvieracie zviera; public Zoo () {}} abstraktná trieda Zviera {verejné Názov reťazca; public Animal () {}} trieda Cat rozširuje Animal {public int lives; public Cat () {}}
Keď sa pokúsime deserializovať súbor JSON String inštancii Zoo hodí „Výnimku Jsonmapping: Can Can Construct Instance Of“ ako v nasledujúcom príklade:
@Test (očakáva sa = JsonMappingException.class) public void givenAbstractClass_whenDeserializing_thenException () vyvolá IOException {String json = "{" animal ": {" name ":" lacy "}}"; ObjectMapper mapovač = nový ObjectMapper (); mapper.reader (). forType (Zoo.class) .readValue (json); }
The úplná výnimka je:
com.fasterxml.jackson.databind.JsonMappingException: Nie je možné vytvoriť inštanciu org.baeldung.jackson.exception. Zviera, problém: abstraktné typy musia byť namapované na konkrétne typy, majú vlastný deserializátor alebo musia byť inštancované s ďalšími informáciami o type na [Zdroj: {"animal": {"name": "lacy"}}; riadok: 1, stĺpec: 2] (prostredníctvom referenčného reťazca: org.baeldung.jackson.exception.Zoo ["zviera"]) na adrese c.f.j.d.JsonMappingException.from (JsonMappingException.java:148)
2.2. Riešenia
Problém môžeme vyriešiť jednoduchou anotáciou - @JsonDeserialize v abstraktnej triede:
@JsonDeserialize (as = Cat.class) abstraktná trieda Zviera {...}
Ak máme viac ako jeden podtyp abstraktnej triedy, mali by sme zvážiť zahrnutie informácií o podtype, ktoré sú uvedené v tomto príspevku: Dedenie s Jacksonom.
3. JsonMappingException: Žiadny vhodný konštruktor
3.1. Problém
Teraz - pozrime sa na spoločnú výnimku Jsonmapping: Žiadny vhodný konštruktor nájdené pre typ.
Táto výnimka je vyvolaná, ak Jackson nemá prístup ku konštruktorovi.
V nasledujúcom príklade - trieda Používateľ nemá predvoleného konštruktora:
public class User {public int id; verejné meno reťazca; public User (int id, String name) {this.id = id; this.name = meno; }}
Pri pokuse o deserializáciu reťazca JSON na používateľa sa vyvolá výnimka „Jsonmappingexception: Nenašiel sa žiadny vhodný konštruktor“ - ako v nasledujúcom príklade:
@Test (očakáva sa = JsonMappingException.class) public void givenNoDefaultConstructor_whenDeserializing_thenException () vyvolá IOException {String json = "{" id ": 1," name ":" John "}"; ObjectMapper mapovač = nový ObjectMapper (); mapper.reader (). forType (User.class) .readValue (json); }
The úplná výnimka je:
com.fasterxml.jackson.databind.JsonMappingException: Nenašiel sa žiadny vhodný konštruktor pre typ [jednoduchý typ, trieda org.baeldung.jackson.exception.User]: nemožno vytvoriť inštanciu z objektu JSON (je potrebné pridať / povoliť informácie o type?) na [ Zdroj: {"id": 1, "name": "John"}; riadok: 1, stĺpec: 2] na adrese c.f.j.d.JsonMappingException.from (JsonMappingException.java:148)
3.2. Riešenie
Ak chcete vyriešiť tento problém - stačí pridať predvolený konštruktor ako v nasledujúcom príklade:
public class User {public int id; verejné meno reťazca; public User () {super (); } public User (int id, String name) {this.id = id; this.name = meno; }}
Teraz, keď deserializujeme - proces bude fungovať celkom dobre:
@ Test public void givenDefaultConstructor_whenDeserializing_thenCorrect () vyvolá IOException {String json = "{" id ": 1," name ":" John "}"; ObjectMapper mapovač = nový ObjectMapper (); Používateľ user = mapper.reader () .forType (User.class) .readValue (json); assertEquals ("John", meno_uzivatela); }
4. JsonMappingException: Koreňový názov sa nezhoduje
4.1. Problém
Ďalej - poďme sa pozrieť na výnimku Jsonmapping: Očakávaný koreňový názov sa nezhoduje.
Táto výnimka je vyvolaná, ak súbor JSON sa nezhoduje presne s tým, čo Jackson hľadá; napríklad hlavný JSON môže byť zabalený ako v nasledujúcom príklade:
@Test (očakáva sa = JsonMappingException.class) public void givenWrappedJsonString_whenDeserializing_thenException () vyvolá IOException {String json = "{" user ": {" id ": 1," name ":" John "}}"; ObjectMapper mapovač = nový ObjectMapper (); mapper.enable (DeserializationFeature.UNWRAP_ROOT_VALUE); mapper.reader (). forType (User.class) .readValue (json); }
The úplná výnimka je:
com.fasterxml.jackson.databind.JsonMappingException: koreňový názov „user“ sa nezhoduje s očakávaním („User“) pre typ [jednoduchý typ, trieda org.baeldung.jackson.dtos.User] na adrese [Zdroj: {„používateľ“: {"id": 1, "name": "John"}}; riadok: 1, stĺpec: 2] na adrese c.f.j.d.JsonMappingException.from (JsonMappingException.java:148)
4.2. Riešenie
Tento problém môžeme vyriešiť pomocou anotácie @JsonRootName - ako v nasledujúcom príklade:
@JsonRootName (hodnota = "užívateľ") verejná trieda UserWithRoot {verejné int id; verejné meno reťazca; }
Keď sa pokúsime deserializovať zabalený JSON - funguje to správne:
@Test public void givenWrappedJsonStringAndConfigureClass_whenDeserializing_thenCorrect () vyvolá IOException {String json = "{" user ": {" id ": 1," name ":" John "}}"; ObjectMapper mapovač = nový ObjectMapper (); mapper.enable (DeserializationFeature.UNWRAP_ROOT_VALUE); UserWithRoot user = mapper.reader () .forType (UserWithRoot.class) .readValue (json); assertEquals ("John", meno uzivatela); }
5. JsonMappingException: Pre triedu sa nenašiel žiadny serializátor
5.1. Problém
Teraz - poďme sa pozrieť na výnimku Jsonmapping: Pre triedu sa nenašiel žiadny serializátor.
Táto výnimka je vyvolaná, ak sa o to pokúsite serializovať inštanciu, zatiaľ čo jej vlastnosti a ich getre sú súkromné.
V nasledujúcom príklade sa pokúsime serializovať „UserWithPrivateFields“:
verejná trieda UserWithPrivateFields {int id; Názov reťazca; }
Keď sa pokúsime serializovať inštanciu „UserWithPrivateFields”- vyvolá sa výnimka„ Jsonmappingexception: No Classializer Found for Class “, ako v nasledujúcom príklade:
@Test (očakáva sa = JsonMappingException.class) public void givenClassWithPrivateFields_whenSerializing_thenException () hodí IOException {UserWithPrivateFields user = new UserWithPrivateFields (1, "John"); ObjectMapper mapovač = nový ObjectMapper (); mapper.writer (). writeValueAsString (užívateľ); }
Úplná výnimka je:
com.fasterxml.jackson.databind.JsonMappingException: Nenašiel sa žiadny serializátor pre triedu org.baeldung.jackson.exception.UserWithPrivateFields a nezistili sa žiadne vlastnosti potrebné na vytvorenie BeanSerializer (aby sa zabránilo výnimke, zakážte SerializationFeature.FAIL_ON_EMPTY_BEANS)) na adrese cfjdser.imer.pler.pler.imer failForEmpty (UnknownSerializer.java:59)
5.2. Riešenie
Tento problém môžeme vyriešiť konfiguráciou ObjectMapper viditeľnosť - ako v nasledujúcom príklade:
@ Test public void givenClassWithPrivateFields_whenConfigureSerializing_thenCorrect () vyvolá IOException {UserWithPrivateFields user = new UserWithPrivateFields (1, "John"); ObjectMapper mapovač = nový ObjectMapper (); mapper.setVisibility (PropertyAccessor.FIELD, Visibility.ANY); Výsledok reťazca = mapper.writer (). WriteValueAsString (užívateľ); assertThat (result, containsString ("John")); }
Alebo pomocou anotácie @JsonAutoDetect - ako v nasledujúcom príklade:
@JsonAutoDetect (fieldVisibility = Visibility.ANY) verejná trieda UserWithPrivateFields {...}
Samozrejme, ak máme možnosť upraviť zdroj triedy, môžeme pridať aj getre, ktoré Jackson použije.
6. JsonMappingException: Nie je možné deserializovať inštanciu z
6.1. Problém
Ďalej - pozrime sa na Jsonmappingexception: Can not Deserialize Instance Of.
Táto výnimka je vyvolaná, ak používa sa nesprávny typ pri deserializácii.
V nasledujúcom príklade - sa pokúšame deserializovať a Zoznam z Používateľ:
@Test (očakáva sa = JsonMappingException.class) public void givenJsonOfArray_whenDeserializing_thenException () vyvolá JsonProcessingException, IOException {String json = "[{" id ": 1," name ":" John "}, {" id ": 2," name " : "Adam"}] "; ObjectMapper mapovač = nový ObjectMapper (); mapper.reader (). forType (User.class) .readValue (json); }
The úplná výnimka je:
com.fasterxml.jackson.databind.JsonMappingException: Nie je možné deserializovať inštanciu org.baeldung.jackson.dtos.User out of START_ARRAY token at [Source: [{"id": 1, "name": "John"}, { "id": 2, "name": "Adam"}]; riadok: 1, stĺpec: 1] na adrese c.f.j.d.JsonMappingException.from (JsonMappingException.java:148)
6.2. Riešenie
Tento problém môžeme vyriešiť zmenou typu z Používateľ do Zoznam - ako v nasledujúcom príklade:
@Test public void givenJsonOfArray_whenDeserializing_thenCorrect () vyhodí JsonProcessingException, IOException {String json = "[{" id ": 1," name ":" John "}, {" id ": 2," name ":" Adam "}]" " ; ObjectMapper mapovač = nový ObjectMapper (); Zoznam používateľov = mapper.reader () .forType (nový TypeReference() {}) .readValue (json); assertEquals (2, users.size ()); }
7. UnrecognizedPropertyException
7.1. Problém
Teraz - pozrime sa na UnrecognizedPropertyException.
Táto výnimka je vyvolaná, ak existuje neznáma vlastnosť v JSON Reťazec počas deserializácie.
V nasledujúcom príklade - pokúsime sa deserializovať reťazec JSON s extra vlastnosťou “skontrolované“:
@Test (expect = UnrecognizedPropertyException.class) public void givenJsonStringWithExtra_whenDeserializing_thenException () vyvolá IOException {String json = "{" id ": 1," name ":" John "," checked ": true}"; ObjectMapper mapovač = nový ObjectMapper (); mapper.reader (). forType (User.class) .readValue (json); }
The úplná výnimka je:
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Nerozpoznané pole „začiarknuté“ (trieda org.baeldung.jackson.dtos.User), neoznačené ako ignorovateľné (2 známe vlastnosti: „id“, „meno“]) na adrese [ Zdroj: {"id": 1, "name": "John", "checked": true}; riadok: 1, stĺpec: 38] (prostredníctvom referenčného reťazca: org.baeldung.jackson.dtos.User ["zaškrtnuté"]) na adrese c.f.j.d.exc.UnrecognizedPropertyException.from (UnrecognizedPropertyException.java:51)
7.2. Riešenie
Tento problém môžeme vyriešiť konfiguráciou ObjectMapper - ako v nasledujúcom príklade:
@ Test public void givenJsonStringWithExtra_whenConfigureDeserializing_thenCorrect () hodí IOException {String json = "{" id ": 1," name ":" John "," checked ": true}"; ObjectMapper mapovač = nový ObjectMapper (); mapper.disable (DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); Používateľ user = mapper.reader (). ForType (User.class) .readValue (json); assertEquals ("John", meno_uzivatela); }
Alebo môžeme použiť anotáciu @JsonIgnoreProperties:
@JsonIgnoreProperties (ignoreUnknown = true) používateľ verejnej triedy {...}
8. JsonParseException: Neočakávaný znak (”(kód 39))
8.1. Problém
Ďalej - poďme diskutovať JsonParseException: Neočakávaný znak („“ (kód 39)).
Táto výnimka je vyvolaná, ak reťazec JSON, ktorý sa má deserializovať, obsahuje jednoduché úvodzovky namiesto dvojitých úvodzoviek.
V nasledujúcom príklade sa pokúsime deserializovať reťazec JSON obsahujúci jednoduché úvodzovky:
@Test (očakáva sa = JsonParseException.class) public void givenStringWithSingleQuotes_whenDeserializing_thenException () vyvolá JsonProcessingException, IOException {String json = "{'id': 1, 'name': 'John'}"; ObjectMapper mapovač = nový ObjectMapper (); mapper.reader () .forType (User.class) .readValue (json); }
The úplná výnimka je:
com.fasterxml.jackson.core.JsonParseException: Neočakávaný znak ('' (kód 39)): očakával dvojitú úvodzovku, aby začal názov poľa na [Zdroj: {'id': 1, 'name': 'John'} ; riadok: 1, stĺpec: 3] pri c.f.j.core.JsonParser._constructError (JsonParser.java:1419)
8.2. Riešenie
Môžeme to vyriešiť konfiguráciou ObjectMapper povoliť jednoduché úvodzovky:
@Test public void givenStringWithSingleQuotes_whenConfigureDeserializing_thenCorrect () vyvolá JsonProcessingException, IOException {String json = "{'id': 1, 'name': 'John'}"; JsonFactory factory = nový JsonFactory (); factory.enable (JsonParser.Feature.ALLOW_SINGLE_QUOTES); ObjectMapper mapovač = nový ObjectMapper (továreň); Používateľ user = mapper.reader (). ForType (User.class) .readValue (json); assertEquals ("John", meno uzivatela); }
9. Jackson NoSuchMethodError
Na záver - poďme rýchlo diskutovať o Jacksonových chybách „Žiadna takáto metóda“.
Kedy java.lang.NoSuchMethodError Vyvolá sa výnimka, je to zvyčajne preto, že na svojej triednej ceste máte viac (a nekompatibilných) verzií pohárov Jackson.
The úplná výnimka je:
java.lang.NoSuchMethodError: com.fasterxml.jackson.core.JsonParser.getValueAsString () Ljava / lang / String; na adrese c.f.j.d.deser.std.StringDeserializer.deserialize (StringDeserializer.java:24)
10. Záver
V tomto článku sme sa podrobne ponorili najbežnejšie Jacksonove problémy - výnimky a chyby, pri pohľade na možné príčiny a na riešenie každej z nich.
Implementácia všetkých týchto príkladov a útržkov kódu nájdete na Githube - toto je projekt založený na Maven, takže by malo byť ľahké ho importovať a spustiť tak, ako je.