Jackson uitzonderingen - problemen en oplossingen

1. Overzicht

In deze tutorial gaan we verder de meest voorkomende Jackson-uitzonderingen - de JsonMappingException en UnrecognizedPropertyException.

Tot slot - we zullen Jackson kort bespreken dat dergelijke methodefouten niet zijn.

2. “JsonMappingException: Kan geen instantie construeren van '

2.1. Het probleem

Laten we eerst eens kijken naar Jsonmappingexception: Can Not Construct Instance Of.

Deze uitzondering wordt gegenereerd als Jackson kan geen instantie van de klas maken - dit gebeurt als de klas is abstract of het is gewoon een koppel.

In het volgende voorbeeld proberen we een instantie uit class te deserialiseren Dierentuin die een eigenschap heeft dier met abstract type Dier:

openbare klasse Dierentuin {openbaar Dierlijk dier; public Zoo () {}} abstracte klasse Animal {public String naam; public Animal () {}} class Cat verlengt Animal {public int lives; openbare kat () {}}

Wanneer we proberen een JSON te deserialiseren Draad naar Zoo-instantie gooit het de "Jsonmappingexception: Can Not Construct Instance Of" zoals in het volgende voorbeeld:

@Test (verwacht = JsonMappingException.class) public void givenAbstractClass_whenDeserializing_thenException () gooit IOException {String json = "{" animal ": {" name ":" lacy "}}"; ObjectMapper-mapper = nieuwe ObjectMapper (); mapper.reader (). forType (Zoo.class) .readValue (json); }

De volledige uitzondering is:

com.fasterxml.jackson.databind.JsonMappingException: kan instantie van org.baeldung.jackson.exception.Animal niet construeren, probleem: abstracte typen moeten ofwel worden toegewezen aan concrete typen, een aangepaste deserializer hebben of worden geïnstantieerd met aanvullende type-informatie op [Bron: {"dier": {"naam": "lacy"}}; regel: 1, kolom: 2] (via referentieketen: org.baeldung.jackson.exception.Zoo ["dier"]) op c.f.j.d. JsonMappingException.from (JsonMappingException.java:148)

2.2. Oplossingen

We kunnen het probleem oplossen met een eenvoudige annotatie - @JsonDeserialize op de abstracte klasse:

@JsonDeserialize (as = Cat.class) abstracte klasse Dier {...}

Als we meer dan één subtype van de abstracte klasse hebben, dan zouden we moeten overwegen om subtype-informatie op te nemen zoals getoond in dit bericht: Overerving met Jackson.

3. JsonMappingException: Geen geschikte constructeur

3.1. Het probleem

Laten we nu eens kijken naar de algemene Jsonmapping-uitzondering: geen geschikte constructor gevonden voor type.

Deze uitzondering wordt gegenereerd als Jackson heeft geen toegang tot de constructor.

In het volgende voorbeeld - class Gebruiker heeft geen standaard constructor:

openbare klasse Gebruiker {openbare int id; public String naam; openbare gebruiker (int id, stringnaam) {this.id = id; this.name = naam; }}

Wanneer we proberen een JSON-string naar de gebruiker te deserialiseren, wordt een uitzondering "Jsonmappingexception: No Suitable Constructor found" gegenereerd - zoals in het volgende voorbeeld:

@Test (verwacht = JsonMappingException.class) public void givenNoDefaultConstructor_whenDeserializing_thenException () gooit IOException {String json = "{" id ": 1," name ":" John "}"; ObjectMapper-mapper = nieuwe ObjectMapper (); mapper.reader (). forType (User.class) .readValue (json); }

De volledige uitzondering is:

com.fasterxml.jackson.databind.JsonMappingException: Geen geschikte constructor gevonden voor type [eenvoudig type, klasse org.baeldung.jackson.exception.User]: kan niet instantiëren vanuit JSON-object (moet type-informatie worden toegevoegd / ingeschakeld?) bij [ Bron: {"id": 1, "name": "John"}; regel: 1, kolom: 2] op c.f.j.d.JsonMappingException.from (JsonMappingException.java:148)

3.2. De oplossing

Om dit probleem op te lossen, voegt u gewoon een standaardconstructor toe zoals in het volgende voorbeeld:

openbare klasse Gebruiker {openbare int id; public String naam; openbare gebruiker () {super (); } openbare gebruiker (int id, stringnaam) {this.id = id; this.name = naam; }}

Als we nu deserialiseren, werkt het proces prima:

@Test openbare leegte gegevenDefaultConstructor_whenDeserializing_thenCorrect () gooit IOException {String json = "{" id ": 1," name ":" John "}"; ObjectMapper-mapper = nieuwe ObjectMapper (); Gebruiker user = mapper.reader () .forType (User.class) .readValue (json); assertEquals ("John", user.name); }

4. JsonMappingException: Hoofdnaam komt niet overeen met verwacht

4.1. Het probleem

Vervolgens - laten we eens kijken naar Jsonmappingexception: Root Name komt niet overeen met verwacht.

Deze uitzondering wordt gegenereerd als de JSON komt niet precies overeen met wat Jackson zoekt; de hoofd-JSON kan bijvoorbeeld worden verpakt zoals in het volgende voorbeeld:

@Test (verwacht = JsonMappingException.class) public void givenWrappedJsonString_whenDeserializing_thenException () gooit IOException {String json = "{" user ": {" id ": 1," name ":" John "}}"; ObjectMapper-mapper = nieuwe ObjectMapper (); mapper.enable (DeserializationFeature.UNWRAP_ROOT_VALUE); mapper.reader (). forType (User.class) .readValue (json); }

De volledige uitzondering is:

com.fasterxml.jackson.databind.JsonMappingException: Rootnaam 'gebruiker' komt niet overeen met verwachte ('Gebruiker') voor type [eenvoudig type, klasse org.baeldung.jackson.dtos.User] op [Bron: {"gebruiker": {"id": 1, "name": "John"}}; regel: 1, kolom: 2] op c.f.j.d.JsonMappingException.from (JsonMappingException.java:148) 

4.2. De oplossing

We kunnen dit probleem oplossen met behulp van de annotatie @JsonRootName - zoals in het volgende voorbeeld:

@JsonRootName (waarde = "gebruiker") openbare klasse UserWithRoot {openbare int id; public String naam; }

Wanneer we proberen de ingepakte JSON te deserialiseren, werkt het correct:

@Test openbare ongeldig gegevenWrappedJsonStringAndConfigureClass_whenDeserializing_thenCorrect () gooit IOException {String json = "{" user ": {" id ": 1," name ":" John "}}"; ObjectMapper-mapper = nieuwe ObjectMapper (); mapper.enable (DeserializationFeature.UNWRAP_ROOT_VALUE); UserWithRoot gebruiker = mapper.reader () .forType (UserWithRoot.class) .readValue (json); assertEquals ("John", user.name); }

5. JsonMappingException: Geen Serializer gevonden voor Klasse

5.1. Het probleem

Laten we nu eens kijken naar Jsonmappingexception: No Serializer Found for Class.

Deze uitzondering wordt gegenereerd als u dit probeert serialiseer een instantie terwijl de eigenschappen en hun getters privé zijn.

In het volgende voorbeeld proberen we een "UserWithPrivateFields“:

openbare klasse UserWithPrivateFields {int id; String naam; }

Wanneer we een instantie van 'UserWithPrivateFields"- een uitzondering" Jsonmappingexception: No Serializer Found for Class "wordt gegenereerd zoals in het volgende voorbeeld:

@Test (verwacht = JsonMappingException.class) public void givenClassWithPrivateFields_whenSerializing_thenException () gooit IOException {UserWithPrivateFields user = nieuwe UserWithPrivateFields (1, "John"); ObjectMapper-mapper = nieuwe ObjectMapper (); mapper.writer (). writeValueAsString (gebruiker); }

De volledige uitzondering is:

com.fasterxml.jackson.databind.JsonMappingException: geen serializer gevonden voor klasse org.baeldung.jackson.exception.UserWithPrivateFields en er zijn geen eigenschappen ontdekt om BeanSerializer te maken (om uitzondering te voorkomen, schakel SerializationFeature.FAIL_ON_EMPTY_BEANS)) op cfjdser.Serializer uit. failForEmpty (UnknownSerializer.java:59)

5.2. De oplossing

We kunnen dit probleem oplossen door het ObjectMapper zichtbaarheid - zoals in het volgende voorbeeld:

@Test openbare leegte gegevenClassWithPrivateFields_whenConfigureSerializing_thenCorrect () gooit IOException {UserWithPrivateFields gebruiker = nieuwe UserWithPrivateFields (1, "John"); ObjectMapper-mapper = nieuwe ObjectMapper (); mapper.setVisibility (PropertyAccessor.FIELD, Visibility.ANY); String resultaat = mapper.writer (). WriteValueAsString (gebruiker); assertThat (resultaat, bevatString ("John")); }

Of met behulp van de annotatie @JsonAutoDetect - zoals in het volgende voorbeeld:

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

Als we de optie hebben om de bron van de klasse te wijzigen, kunnen we natuurlijk ook getters toevoegen die Jackson kan gebruiken.

6. JsonMappingException: Kan exemplaar van niet deserialiseren

6.1. Het probleem

Vervolgens - laten we eens kijken naar Jsonmappingexception: Can Not Deserialize Instance Of.

Deze uitzondering wordt gegenereerd als het verkeerde type wordt gebruikt tijdens het deserialiseren.

In het volgende voorbeeld proberen we een Lijst van Gebruiker:

@Test (verwacht = JsonMappingException.class) public void givenJsonOfArray_whenDeserializing_thenException () gooit JsonProcessingException, IOException {String json = "[{" id ": 1," name ":" John "}, {" id ": 2," name " :"Adam"}]"; ObjectMapper-mapper = nieuwe ObjectMapper (); mapper.reader (). forType (User.class) .readValue (json); }

De volledige uitzondering is:

com.fasterxml.jackson.databind.JsonMappingException: kan instantie van org.baeldung.jackson.dtos niet deserialiseren.Gebruiker uit START_ARRAY-token op [Bron: [{"id": 1, "naam": "John"}, { "id": 2, "name": "Adam"}]; regel: 1, kolom: 1] op c.f.j.d.JsonMappingException.from (JsonMappingException.java:148)

6.2. De oplossing

We kunnen dit probleem oplossen door het type te wijzigen van Gebruiker naar Lijst - zoals in het volgende voorbeeld:

@Test openbare leegte gegevenJsonOfArray_whenDeserializing_thenCorrect () gooit JsonProcessingException, IOException {String json = "[{" id ": 1," name ":" John "}, {" id ": 2," name ":" Adam "}]" ; ObjectMapper-mapper = nieuwe ObjectMapper (); Lijst gebruikers = mapper.reader () .forType (nieuw TypeReference() {}) .readValue (json); assertEquals (2, users.size ()); }

7. UnrecognizedPropertyException

7.1. Het probleem

Nu - laten we eens kijken UnrecognizedPropertyException.

Deze uitzondering wordt gegenereerd als er een onbekende eigenschap in de JSON Tekenreeks tijdens het deserialiseren.

In het volgende voorbeeld proberen we een JSON-string te deserialiseren met een extra eigenschap "gecontroleerd“:

@Test (verwacht = UnrecognizedPropertyException.class) openbare ongeldige gegevenJsonStringWithExtra_whenDeserializing_thenException () gooit IOException {String json = "{" id ": 1," naam ":" John "," gecontroleerd ": true}"; ObjectMapper-mapper = nieuwe ObjectMapper (); mapper.reader (). forType (User.class) .readValue (json); }

De volledige uitzondering is:

com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: niet-herkend veld "gecontroleerd" (klasse org.baeldung.jackson.dtos.User), niet gemarkeerd als negeerbaar (2 bekende eigenschappen: "id", "naam"]) bij [ Bron: {"id": 1, "naam": "John", "gecontroleerd": waar}; regel: 1, kolom: 38] (via referentieketen: org.baeldung.jackson.dtos.User ["gecontroleerd"]) op c.f.j.d.exc.UnrecognizedPropertyException.from (UnrecognizedPropertyException.java:51)

7.2. De oplossing

We kunnen dit probleem oplossen door het ObjectMapper - zoals in het volgende voorbeeld:

@Test openbare leegte gegevenJsonStringWithExtra_whenConfigureDeserializing_thenCorrect () gooit IOException {String json = "{" id ": 1," naam ":" John "," gecontroleerd ": true}"; ObjectMapper-mapper = nieuwe ObjectMapper (); mapper.disable (DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); Gebruiker user = mapper.reader (). ForType (User.class) .readValue (json); assertEquals ("John", user.name); }

Of we kunnen de annotatie gebruiken @JsonIgnoreProperties:

@JsonIgnoreProperties (ignoreUnknown = true) openbare klasse Gebruiker {...}

8. JsonParseException: Onverwacht teken ("'(code 39))

8.1. Het probleem

Volgende - laten we bespreken JsonParseException: onverwacht teken ("'(code 39)).

Deze uitzondering wordt gegenereerd als de JSON-string die gedeserialiseerd moet worden, bevat enkele aanhalingstekens in plaats van dubbele aanhalingstekens.

In het volgende voorbeeld proberen we een JSON-string met enkele aanhalingstekens te deserialiseren:

@Test (verwacht = JsonParseException.class) public void givenStringWithSingleQuotes_whenDeserializing_thenException () gooit JsonProcessingException, IOException {String json = "{'id': 1, 'name': 'John'}"; ObjectMapper-mapper = nieuwe ObjectMapper (); mapper.reader () .forType (User.class) .readValue (json); }

De volledige uitzondering is:

com.fasterxml.jackson.core.JsonParseException: onverwacht karakter ('' '(code 39)): verwachtte dat dubbele aanhalingstekens de veldnaam zouden starten bij [Bron: {' id ': 1,' naam ':' John '} ; regel: 1, kolom: 3] op c.f.j.core.JsonParser._constructError (JsonParser.java:1419)

8.2. De oplossing

We kunnen dit oplossen door het ObjectMapper om enkele aanhalingstekens toe te staan:

@Test openbare leegte gegevenStringWithSingleQuotes_whenConfigureDeserializing_thenCorrect () gooit JsonProcessingException, IOException {String json = "{'id': 1, 'name': 'John'}"; JsonFactory factory = nieuwe JsonFactory (); factory.enable (JsonParser.Feature.ALLOW_SINGLE_QUOTES); ObjectMapper-mapper = nieuwe ObjectMapper (fabriek); Gebruiker user = mapper.reader (). ForType (User.class) .readValue (json); assertEquals ("John", user.name); }

9. Jackson NoSuchMethodError

Tot slot - laten we het snel hebben over de Jackson "No such method" -fouten.

Wanneer java.lang.NoSuchMethodError Er wordt een uitzondering gemaakt, dit komt meestal doordat je meerdere (en incompatibele) versies van Jackson-jars op je klassenpad hebt staan.

De volledige uitzondering is:

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

10. Conclusie

In dit artikel hebben we er een diepe duik in gedaan de meest voorkomende Jackson-problemen - uitzonderingen en fouten, waarbij we kijken naar de mogelijke oorzaken en naar de oplossingen voor elk.

De implementatie van al deze voorbeelden en codefragmenten is te vinden op Github - dit is een op Maven gebaseerd project, dus het zou gemakkelijk moeten kunnen worden geïmporteerd en uitgevoerd zoals het is.