Jackson-Ausnahmen - Probleme und Lösungen

1. Übersicht

In diesem Tutorial werden die häufigsten Jackson-Ausnahmen behandelt - die JsonMappingException und die UnrecognizedPropertyException .

Schließlich - wir werden kurz Jackson keine solchen Methodenfehler diskutieren.

2. " JsonMappingException : Instanz von kann nicht erstellt werden"

2.1. Das Problem

Zuerst - werfen wir einen Blick auf Jsonmappingexception: Can Not Construct Instance Of.

Diese Ausnahme wird ausgelöst, wenn Jackson keine Instanz der Klasse erstellen kann. Dies geschieht, wenn die Klasse abstrakt ist oder nur eine Schnittstelle .

Im folgenden Beispiel versuchen wir, eine Instanz aus der Klasse Zoo zu deserialisieren, die eine Eigenschaft animal mit dem abstrakten Typ Animal hat :

public class Zoo { public Animal animal; public Zoo() { } } abstract class Animal { public String name; public Animal() { } } class Cat extends Animal { public int lives; public Cat() { } }

Wenn wir versuchen , eine JSON deserialisieren String zu Zoo Instanz der wirft „Jsonmappingexception: Kann Construct Instanz nicht“ , wie im folgende Beispiel:

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

Die vollständige Ausnahme ist:

com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of org.baeldung.jackson.exception.Animal, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information at [Source: {"animal":{"name":"lacy"}}; line: 1, column: 2] (through reference chain: org.baeldung.jackson.exception.Zoo["animal"]) at c.f.j.d.JsonMappingException.from(JsonMappingException.java:148)

2.2. Lösungen

Wir können das Problem mit einer einfachen Anmerkung lösen - @JsonDeserialize für die abstrakte Klasse:

@JsonDeserialize(as = Cat.class) abstract class Animal {...}

Wenn wir mehr als einen Subtyp der abstrakten Klasse haben, sollten wir in Betracht ziehen, Subtypinformationen aufzunehmen, wie in diesem Beitrag gezeigt: Vererbung mit Jackson.

3. JsonMappingException : Kein geeigneter Konstruktor

3.1. Das Problem

Schauen wir uns nun die allgemeine Jsonmappingexception an: Kein geeigneter Konstruktor für Typ gefunden .

Diese Ausnahme wird ausgelöst, wenn Jackson nicht auf den Konstruktor zugreifen kann .

Im folgenden Beispiel - Klasse Benutzer hat keinen Standardkonstruktor:

public class User { public int id; public String name; public User(int id, String name) { this.id = id; this.name = name; } }

Wenn wir versuchen, eine JSON-Zeichenfolge für den Benutzer zu deserialisieren, wird eine Ausnahme "Jsonmappingexception: Kein geeigneter Konstruktor gefunden" ausgelöst - wie im folgenden Beispiel:

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

Die vollständige Ausnahme ist:

com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class org.baeldung.jackson.exception.User]: can not instantiate from JSON object (need to add/enable type information?) at [Source: {"id":1,"name":"John"}; line: 1, column: 2] at c.f.j.d.JsonMappingException.from(JsonMappingException.java:148)

3.2. Die Lösung

Um dieses Problem zu lösen, fügen Sie einfach einen Standardkonstruktor wie im folgenden Beispiel hinzu:

public class User { public int id; public String name; public User() { super(); } public User(int id, String name) { this.id = id; this.name = name; } }

Wenn wir jetzt deserialisieren, funktioniert der Prozess einwandfrei:

@Test public void givenDefaultConstructor_whenDeserializing_thenCorrect() throws IOException { String json = "{"id":1,"name":"John"}"; ObjectMapper mapper = new ObjectMapper(); User user = mapper.reader() .forType(User.class).readValue(json); assertEquals("John", user.name); }

4. JsonMappingException : Stammname stimmt nicht mit erwartet überein

4.1. Das Problem

Weiter - werfen wir einen Blick auf die Jsonmappingexception: Root-Name stimmt nicht mit erwartet überein.

Diese Ausnahme wird ausgelöst, wenn der JSON nicht genau dem entspricht, wonach Jackson sucht . Beispielsweise könnte der Haupt-JSON wie im folgenden Beispiel verpackt werden:

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

Die vollständige Ausnahme ist:

com.fasterxml.jackson.databind.JsonMappingException: Root name 'user' does not match expected ('User') for type [simple type, class org.baeldung.jackson.dtos.User] at [Source: {"user":{"id":1,"name":"John"}}; line: 1, column: 2] at c.f.j.d.JsonMappingException.from(JsonMappingException.java:148) 

4.2. Die Lösung

Wir können dieses Problem mit der Anmerkung @JsonRootName lösen - wie im folgenden Beispiel:

@JsonRootName(value = "user") public class UserWithRoot { public int id; public String name; }

Wenn wir versuchen, den verpackten JSON zu deserialisieren, funktioniert er ordnungsgemäß:

@Test public void givenWrappedJsonStringAndConfigureClass_whenDeserializing_thenCorrect() throws IOException { String json = "{"user":{"id":1,"name":"John"}}"; ObjectMapper mapper = new ObjectMapper(); mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE); UserWithRoot user = mapper.reader() .forType(UserWithRoot.class) .readValue(json); assertEquals("John", user.name); }

5. JsonMappingException : Kein Serializer für Klasse gefunden

5.1. Das Problem

Schauen wir uns jetzt Jsonmappingexception an: Kein Serializer für Klasse gefunden.

Diese Ausnahme wird ausgelöst, wenn Sie versuchen, eine Instanz zu serialisieren, während ihre Eigenschaften und ihre Getter privat sind .

Im folgenden Beispiel versuchen wir, ein „ UserWithPrivateFields “ zu serialisieren :

public class UserWithPrivateFields { int id; String name; }

Wenn wir versuchen, eine Instanz von " UserWithPrivateFields " zu serialisieren, wird eine Ausnahme "Jsonmappingexception: Kein Serializer für Klasse gefunden" wie im folgenden Beispiel ausgelöst:

@Test(expected = JsonMappingException.class) public void givenClassWithPrivateFields_whenSerializing_thenException() throws IOException { UserWithPrivateFields user = new UserWithPrivateFields(1, "John"); ObjectMapper mapper = new ObjectMapper(); mapper.writer().writeValueAsString(user); }

Die vollständige Ausnahme ist:

com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class org.baeldung.jackson.exception.UserWithPrivateFields and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) at c.f.j.d.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:59)

5.2. Die Lösung

Wir können dieses Problem lösen, indem wir die ObjectMapper- Sichtbarkeit konfigurieren - wie im folgenden Beispiel:

@Test public void givenClassWithPrivateFields_whenConfigureSerializing_thenCorrect() throws IOException { UserWithPrivateFields user = new UserWithPrivateFields(1, "John"); ObjectMapper mapper = new ObjectMapper(); mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY); String result = mapper.writer().writeValueAsString(user); assertThat(result, containsString("John")); }

Oder verwenden Sie die Anmerkung @JsonAutoDetect - wie im folgenden Beispiel:

@JsonAutoDetect(fieldVisibility = Visibility.ANY) public class UserWithPrivateFields { ... }

Wenn wir die Option haben, die Quelle der Klasse zu ändern, können wir natürlich auch Getter hinzufügen, die Jackson verwenden kann.

6. JsonMappingException: Can Not Deserialize Instance Of

6.1. The Problem

Next – let's take a look at Jsonmappingexception: Can Not Deserialize Instance Of.

This exception is thrown if the wrong type is used while deserializing.

In the following example – we are trying to deserialize a List of User:

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

The full exception is:

com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of org.baeldung.jackson.dtos.User out of START_ARRAY token at [Source: [{"id":1,"name":"John"},{"id":2,"name":"Adam"}]; line: 1, column: 1] at c.f.j.d.JsonMappingException.from(JsonMappingException.java:148)

6.2. The Solution

We can solve this problem by changing the type from User to List – as in the following example:

@Test public void givenJsonOfArray_whenDeserializing_thenCorrect() throws JsonProcessingException, IOException { String json = "[{"id":1,"name":"John"},{"id":2,"name":"Adam"}]"; ObjectMapper mapper = new ObjectMapper(); List users = mapper.reader() .forType(new TypeReference
    
     () {}) .readValue(json); assertEquals(2, users.size()); }
    

7. UnrecognizedPropertyException

7.1. The Problem

Now – let's see the UnrecognizedPropertyException.

This exception is thrown if there is an unknown property in the JSON String while deserializing.

In the following example – we try to deserialize a JSON String with extra property “checked“:

@Test(expected = UnrecognizedPropertyException.class) public void givenJsonStringWithExtra_whenDeserializing_thenException() throws IOException { String json = "{"id":1,"name":"John", "checked":true}"; ObjectMapper mapper = new ObjectMapper(); mapper.reader().forType(User.class).readValue(json); }

The full exception is:

com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "checked" (class org.baeldung.jackson.dtos.User), not marked as ignorable (2 known properties: "id", "name"]) at [Source: {"id":1,"name":"John", "checked":true}; line: 1, column: 38] (through reference chain: org.baeldung.jackson.dtos.User["checked"]) at c.f.j.d.exc.UnrecognizedPropertyException.from( UnrecognizedPropertyException.java:51)

7.2. The Solution

We can solve this problem by configuring the ObjectMapper – as in the following example:

@Test public void givenJsonStringWithExtra_whenConfigureDeserializing_thenCorrect() throws IOException { String json = "{"id":1,"name":"John", "checked":true}"; ObjectMapper mapper = new ObjectMapper(); mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); User user = mapper.reader().forType(User.class).readValue(json); assertEquals("John", user.name); }

Or we can use the annotation @JsonIgnoreProperties:

@JsonIgnoreProperties(ignoreUnknown = true) public class User {...}

8. JsonParseException: Unexpected Character (”' (code 39))

8.1. The Problem

Next – let's discuss JsonParseException: Unexpected character (”' (code 39)).

This exception is thrown if the JSON String to be deserialized contains single quotes instead of double quotes.

In the following example – we try to deserialize a JSON String containing single quotes:

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

The full exception is:

com.fasterxml.jackson.core.JsonParseException: Unexpected character (''' (code 39)): was expecting double-quote to start field name at [Source: {'id':1,'name':'John'}; line: 1, column: 3] at c.f.j.core.JsonParser._constructError(JsonParser.java:1419)

8.2. The Solution

We can solve this by configuring the ObjectMapper to allow single quotes:

@Test public void givenStringWithSingleQuotes_whenConfigureDeserializing_thenCorrect() throws JsonProcessingException, IOException { String json = "{'id':1,'name':'John'}"; JsonFactory factory = new JsonFactory(); factory.enable(JsonParser.Feature.ALLOW_SINGLE_QUOTES); ObjectMapper mapper = new ObjectMapper(factory); User user = mapper.reader().forType(User.class) .readValue(json); assertEquals("John", user.name); }

9. Jackson NoSuchMethodError

Finally – let's quickly discuss the Jackson “No such method” errors.

When java.lang.NoSuchMethodError Exception is thrown, it is usually because you have multiple (and incompatible) versions of Jackson jars on your classpath.

The full exception is:

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

10. Conclusion

In diesem Artikel haben wir uns eingehend mit den häufigsten Jackson-Problemen befasst - Ausnahmen und Fehlern - und dabei die möglichen Ursachen und Lösungen für jedes Problem untersucht .

Die Implementierung all dieser Beispiele und Codefragmente finden Sie auf Github - dies ist ein Maven-basiertes Projekt, daher sollte es einfach zu importieren und auszuführen sein, wie es ist.