Автор оригинала: Eugen Paraschiv.
1. Обзор
В этом учебнике мы пройдемся по наиболее распространенные Джексон Исключения – JsonMappingException и НепризнанныйПропертиЭксцепция .
Наконец – мы кратко обсудим Джексон нет таких ошибок метода.
Дальнейшее чтение:
Джексон — пользовательский сериализатор
Джексон Аннотация Примеры
Начало работы с пользовательской deserialization в Джексон-
2. “JsonMappingException: Не может построить экземпляр”
2.1. Проблема
Во-первых – давайте посмотрим на Jsonmappingexception: Не может построить экземпляр.
Это исключение брошено, если Джексон не может создать экземпляр класса – это происходит, если класс абстрактные или это просто интерфейс .
В следующем примере мы пытаемся deserialize экземпляр из класса Зоопарк который имеет свойство животных с абстрактные тип Защита :
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() { } }
Когда мы пытаемся deserialize JSON Струнные в зоопарк экземпляре он бросает “Jsonmappingexception: Не может построить экземпляр”, как в следующем примере:
@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); }
полное исключение есть:
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. Решения
Мы можем решить проблему с помощью простой аннотации – @JsonDeserialize об абстрактном классе:
@JsonDeserialize(as = Cat.class) abstract class Animal {...}
Если у нас есть более чем один подтип абстрактного класса, то мы должны рассмотреть вопрос о том, в том числе подтипа информации, как показано в этой должности: Наследование с Джексоном .
3. JsonMappingException: Нет подходящего конструктора
3.1. Проблема
Теперь – давайте посмотрим на общие Jsonmappingexception: Нет подходящего конструктора найдено для типа .
Это исключение брошено, если Джексон не может получить доступ к конструктору .
В следующем примере – класс Пользователь не имеет конструктора по умолчанию:
public class User { public int id; public String name; public User(int id, String name) { this.id = id; this.name = name; } }
Когда мы пытаемся deserialize JSON Строка для пользователя Исключение “Jsonmappingexception: Нет подходящий конструктор найден” брошен – как в следующем примере:
@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); }
полное исключение есть:
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. Решение
Чтобы решить эту проблему – просто добавьте конструктора по умолчанию, как в следующем примере:
public class User { public int id; public String name; public User() { super(); } public User(int id, String name) { this.id = id; this.name = name; } }
Теперь, когда мы deserialize – процесс будет работать просто отлично:
@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: Корневое имя не соответствует ожидаемым
4.1. Проблема
Далее – давайте посмотрим на Jsonmappingexception: Корневое имя не соответствует ожидаемым.
Это исключение брошено, если JSON не соответствует именно то, что Джексон ищет ; например, основной JSON может быть обернут, как в следующем примере:
@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); }
полное исключение есть:
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. Решение
Мы можем решить эту проблему с помощью аннотации @JsonRootName – как в следующем примере:
@JsonRootName(value = "user") public class UserWithRoot { public int id; public String name; }
Когда мы пытаемся deserialize завернутый JSON – он работает правильно:
@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: Серийный игрок не найден для класса
5.1. Проблема
Теперь – давайте посмотрим на Jsonmappingexception: Нет Serializer Найдено для класса.
Это исключение брошено, если вы попытаетесь сериализовать экземпляр, в то время как его свойства и их getters являются частными .
В следующем примере мы пытаемся сериализировать « ПользовательWithPrivateFields “:
public class UserWithPrivateFields { int id; String name; }
Когда мы пытаемся сериализировать экземпляр ” ПользовательWithPrivateFields ” – Исключение “Jsonmappingexception: Нет Serializer Найдено для класса” брошен как в следующем примере:
@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); }
Полное исключение:
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. Решение
Мы можем решить эту проблему, настроили ОбъектМаппер видимость – как в следующем примере:
@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")); }
Или с помощью аннотации @JsonAutoDetect – как в следующем примере:
@JsonAutoDetect(fieldVisibility = Visibility.ANY) public class UserWithPrivateFields { ... }
Конечно, если у нас есть возможность изменить источник класса, мы также можем добавить в getters для Джексона в использовании.
6. JsonMappingException: Не может deserialize Экземпляр
6.1. Проблема
Далее – давайте посмотрим на Jsonmappingexception: Не может deserialize Экземпляр.
Это исключение брошено, если используется неправильный тип в то время как deserializing.
В следующем примере – мы пытаемся deserialize Список Пользователь :
@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); }
полное исключение есть:
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. Решение
Мы можем решить эту проблему, изменив тип с Пользователь Список
@Test public void givenJsonOfArray_whenDeserializing_thenCorrect() throws JsonProcessingException, IOException { String json = "[{"id":1,"name":"John"},{"id":2,"name":"Adam"}]"; ObjectMapper mapper = new ObjectMapper(); Listusers = mapper.reader() .forType(new TypeReference >() {}) .readValue(json); assertEquals(2, users.size()); }
7. НепризнаннаяПропертиЭксцепция
7.1. Проблема
Теперь – давайте посмотрим на НепризнанныйПропертиЭксцепция .
Это исключение брошено, если есть неизвестное имущество в Строка в то время как deserializing.
В следующем примере мы пытаемся deserialize JSON String с дополнительным свойством ” проверено “:
@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); }
полное исключение есть:
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. Решение
Мы можем решить эту проблему, настроили ОбъектМаппер – как в следующем примере:
@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); }
Или мы можем использовать аннотацию @JsonIgnoreProperties :
@JsonIgnoreProperties(ignoreUnknown = true) public class User {...}
8. JsonParseException: Неожиданный персонаж (“‘ (код 39))
8.1. Проблема
Далее – давайте обсудим JsonParseException: Неожиданный персонаж (“‘ (код 39)) .
Это исключение брошено, если Строка JSON, которая будет deserialized содержит одиночные цитаты вместо двойных котировок.
В следующем примере мы пытаемся deserialize JSON String, содержащий отдельные цитаты:
@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); }
полное исключение есть:
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. Решение
Мы можем решить эту проблему путем настройки ОбъектМаппер чтобы разрешить одиночные котировки:
@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. Джексон NoSuchMethodError
Наконец – давайте быстро обсудим Джексон “Нет такого метода” ошибки.
Когда java.lang.NoSuchMethodError Исключение брошено, это, как правило, потому, что у вас есть несколько (и несовместимые) версии Джексон банки на вашем classpath.
полное исключение есть:
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. Заключение
В этой статье мы сделали глубокое погружение в наиболее распространенные проблемы Джексона – исключения и ошибки , глядя на потенциальные причины и на решения для каждого из них.
Реализация всех этих примеров и фрагментов кода можно найти на Гитхуб – это Maven основе проекта, поэтому она должна быть легко импортировать и работать, как она есть.