Jackson Ausnahmen - Probleme und Lösungen

Jackson-Ausnahmen - Probleme und Lösungen

1. Überblick

In diesem Tutorial gehen wir überthe most common Jackson Exceptions -JsonMappingException undUnrecognizedPropertyException.

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

Weitere Lektüre:

Jackson - Benutzerdefinierter Serializer

Steuern Sie Ihre JSON-Ausgabe mit Jackson 2 mithilfe eines benutzerdefinierten Serializers.

Read more

Beispiele für Jackson-Anmerkungen

Der Kern von Jackson besteht im Wesentlichen aus einer Reihe von Anmerkungen - stellen Sie sicher, dass Sie diese gut verstehen.

Read more

Erste Schritte mit der benutzerdefinierten Deserialisierung in Jackson

Verwenden Sie Jackson, um benutzerdefiniertes JSON einem beliebigen Java-Entitätsdiagramm mit vollständiger Kontrolle über den Deserialisierungsprozess zuzuordnen.

Read more

2. “JsonMappingException: Instanz von kann nicht konstruiert werden”

2.1. Das Problem

Schauen wir uns zunächst die Jsonmappingexception an: Instanz von kann nicht konstruiert werden.

Diese Ausnahme wird ausgelöst, wennJackson can’t create an instance of the class - dies geschieht, wenn die Klasseabstract oder nurinterface ist.

Im folgenden Beispiel versuchen wir, eine Instanz aus der KlasseZoo zu deserialisieren, die eine Eigenschaftanimal mitabstract TypAnimal 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 JSONString in eine Zoo-Instanz zu deserialisieren, wird die "Jsonmappingexception: Can Not Construct Instance Of" wie im folgenden Beispiel ausgelöst:

@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);
}

Dasfull exception ist:

com.fasterxml.jackson.databind.JsonMappingException:
Can not construct instance of org.example.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.example.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 Annotation lösen -@JsonDeserialize in der abstrakten 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:Inheritance with Jackson.

3. JsonMappingException: Kein geeigneter Konstruktor

3.1. Das Problem

Schauen wir uns nun die allgemeine Jsonmappingexception an: Kein geeigneter Konstruktor found for type.

Diese Ausnahme wird ausgelöst, wennJackson can’t access the constructor.

Im folgenden Beispiel hat die KlasseUserkeinen 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 "Jsonmapping-Ausnahme: 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);
}

Dasfull exception ist:

com.fasterxml.jackson.databind.JsonMappingException:
No suitable constructor found for type
[simple type, class org.example.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, wennthe JSON doesn’t match exactly what Jackson is looking for; 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);
}

Dasfull exception ist:

com.fasterxml.jackson.databind.JsonMappingException:
Root name 'user' does not match expected ('User') for type
 [simple type, class org.example.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 Annotation@JsonRootName lösen - wie im folgenden Beispiel:

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

Wenn wir versuchen, den umschlossenen JSON zu deserialisieren, funktioniert das korrekt:

@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,serialize an instance while its properties and their getters are private.

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 volle Ausnahme ist:

com.fasterxml.jackson.databind.JsonMappingException:
No serializer found for class org.example.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 Sichtbarkeit vonObjectMapperkonfigurieren - 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 Annotation@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 Getters hinzufügen, die Jackson verwenden soll.

6. JsonMappingException: Instanz von kann nicht deserialisiert werden

6.1. Das Problem

Weiter - werfen wir einen Blick auf Jsonmappingexception: Instanz von kann nicht deserialisiert werden.

Diese Ausnahme wird ausgelöst, wennthe wrong type is used während der Deserialisierung vorhanden ist.

Im folgenden Beispiel versuchen wir,List vonUser zu deserialisieren:

@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);
}

Dasfull exception ist:

com.fasterxml.jackson.databind.JsonMappingException:
Can not deserialize instance of
  org.example.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. Die Lösung

Wir können dieses Problem lösen, indem wir den Typ vonUser inList<User> ändern - wie im folgenden Beispiel:

@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. Das Problem

Nun - sehen wir uns dieUnrecognizedPropertyException an.

Diese Ausnahme wird ausgelöst, wenn beim Deserialisieren einunknown property in the JSON String vorhanden ist.

Im folgenden Beispiel versuchen wir, einen JSON-String mit der zusätzlichen Eigenschaft „checked“ zu deserialisieren:

@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);
}

Dasfull exception ist:

com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException:
Unrecognized field "checked" (class org.example.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.example.jackson.dtos.User["checked"])
  at c.f.j.d.exc.UnrecognizedPropertyException.from(
    UnrecognizedPropertyException.java:51)

7.2. Die Lösung

Wir können dieses Problem lösen, indem wirObjectMapper konfigurieren - wie im folgenden Beispiel:

@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);
}

Oder wir können die Annotation@JsonIgnoreProperties verwenden:

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

8. JsonParseException: Unerwartetes Zeichen (”'(Code 39))

8.1. Das Problem

Weiter - lassen Sie unsJsonParseException: Unexpected character (”' (code 39)) diskutieren.

Diese Ausnahme wird ausgelöst, wennthe JSON String to be deserialized contains single quotes anstelle von doppelten Anführungszeichen steht.

Im folgenden Beispiel wird versucht, eine JSON-Zeichenfolge mit einfachen Anführungszeichen zu deserialisieren:

@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);
}

Dasfull exception ist:

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. Die Lösung

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.

Dasfull exception ist:

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. Fazit

In this article, we did a deep dive in the most common Jackson problems – exceptions and errors, looking at the potential causes and at the solutions for each one.

Die Implementierung all dieser Beispiele und Codefragmentecan be found on Github - dies ist ein Maven-basiertes Projekt, daher sollte es einfach zu importieren und auszuführen sein, wie es ist.