ObjectMapper.readValue: примеры (JAVA)

Десериализация JSON с помощью Jackson ObjectMapper
Раздел: Работа с JSON (Jackson, Gson, JSON-P)
ObjectMapper.readValue(String content, Class valueType): T

Описание метода ObjectMapper.readValue и его назначение

Метод ObjectMapper.readValue из библиотеки Jackson служит для десериализации JSON-данных в объекты Java. Вызовы этого метода принимают источник JSON (строка, массив байт, поток, файл и т. п.) и описание целевого типа (Class, TypeReference, JavaType), после чего возвращают объект заданного типа либо выбрасывают исключение при ошибке парсинга или несовместимости типов.

Типичный сценарий применения включает чтение HTTP-ответа, содержимого файла конфигурации или входных данных из потока и преобразование их в POJO, коллекции, массивы или узлы дерева JSON (JsonNode).

Ниже перечислены наиболее распространенные перегрузки метода и их семантика:

  • readValue(String content, Class<T> valueType) - десериализация из строки JSON в объект типа T.
  • readValue(byte[] src, Class<T> valueType) - десериализация из массива байт.
  • readValue(byte[] src, int offset, int len, Class<T> valueType) - десериализация из части массива байт, полезно при буферизации данных.
  • readValue(InputStream src, Class<T> valueType) - чтение из потока, применяется при работе с сетевыми или файловыми потоками.
  • readValue(Reader src, Class<T> valueType) - чтение из Reader (BufferedReader, StringReader и т. п.).
  • readValue(File src, Class<T> valueType) - десериализация из файла.
  • readValue(URL src, Class<T> valueType) - загрузка JSON по URL и десериализация.
  • readValue(JsonParser p, Class<T> valueType) - десериализация, используя уже созданный JsonParser; используется при низкоуровневой обработке токенов или в парсере потоков.
  • readValue(String content, TypeReference<T> valueTypeRef) - вариант для параметризованных типов (например, List<MyType>), где Class не достаточен из‑за type erasure.
  • readValue(byte[] src, TypeReference<T> valueTypeRef) - аналогично для байтовых данных с TypeReference.

Возвращаемое значение: объект типа T (или коллекция/массив/JsonNode и т. п.). При ошибках метод бросает исключение: обычно com.fasterxml.jackson.core.JsonParseException для синтаксических ошибок и com.fasterxml.jackson.databind.JsonMappingException (включая подклассы MismatchedInputException, UnrecognizedPropertyException) при несоответствии типов. Так как большинство перегрузок бросают IOException, их следует обрабатывать либо пробрасывать дальше.

Для сложных/параметризованных типов рекомендуется использовать TypeReference<T> или строить JavaType через TypeFactory, т. к. простого Class<T> бывает недостаточно для сохранения информации о параметрах типа.

Короткие примеры различных вариантов использования

Примеры демонстрируют код и ожидаемый результат. В примерах используется зависимость com.fasterxml.jackson.databind.ObjectMapper.

1) Простая десериализация строки в POJO

public class User {
    public String name;
    public int age;
}

ObjectMapper mapper = new ObjectMapper();
String json = "{\"name\":\"Ivan\",\"age\":30}";
User u = mapper.readValue(json, User.class);
System.out.println(u.name + ":" + u.age);
Ivan:30

2) Десериализация в Map

String json = "{\"k\":1,\"v\":true}";
Map<String, Object> map = mapper.readValue(json, new TypeReference<Map<String, Object>>(){});
System.out.println(map);
{k=1, v=true}

3) Список строк с TypeReference

String json = "[\"a\",\"b\"]";
List<String> list = mapper.readValue(json, new TypeReference<List<String>>(){});
System.out.println(list);
[a, b]

4) Чтение из InputStream

byte[] data = "{\"name\":\"Oleg\",\"age\":25}".getBytes(StandardCharsets.UTF_8);
InputStream in = new ByteArrayInputStream(data);
User u2 = mapper.readValue(in, User.class);
System.out.println(u2.name + ", " + u2.age);
Oleg, 25

5) Частичная десериализация из массива байт

byte[] buf = ("garbage" + "{\"name\":\"Nina\",\"age\":27}").getBytes();
// допустим JSON начинается с смещения 7
User u3 = mapper.readValue(buf, 7, buf.length - 7, User.class);
System.out.println(u3.name);
Nina

6) Использование JsonParser

JsonFactory f = mapper.getFactory();
JsonParser p = f.createParser("{\"name\":\"Ann\",\"age\":22}");
User a = mapper.readValue(p, User.class);
System.out.println(a.name + " " + a.age);
Ann 22

Аналоги и близкие API внутри экосистемы Java

В рамках Jackson существуют похожие по назначению методы и классы с особыми преимуществами:

  • readTree(String) - возвращает JsonNode, полезно при динамической навигации по структуре JSON без привязки к POJO.
  • treeToValue(JsonNode, Class<T>) - преобразование узла дерева в POJO; удобно при частичной обработки дерева.
  • ObjectReader.readValues - возвращает MappingIterator<T> для потоковой десериализации нескольких объектов подряд (например, newline-delimited JSON).
  • readerForUpdating(T valueToUpdate) в ObjectMapper/ObjectReader - обновление существующего объекта полями из JSON вместо создания нового.
  • XmlMapper (Jackson module) - аналогичный API для XML; применяется при работе с XML вместо JSON.

При наличии параллельных требований: динамическая обработка - предпочтительнее readTree/JsonNode, потоковая десериализация больших последовательностей - readerFor / readValues. Для параметризованных типов удобнее ObjectReader с предварительно настроенным JavaType.

Сопоставимые механизмы парсинга JSON в других языках

Краткие альтернативы в популярных языках и их отличия от Java/Jackson:

  • JavaScript: JSON.parse. Простая десериализация в объект/массив, нет встроенной типизации; пример:
    const obj = JSON.parse('{"a":1}');
    console.log(obj.a);
    1
  • Python: json.loads. Возвращает dict/list. Для строгой валидации типов используются pydantic или dataclasses + dacite.
    import json
    obj = json.loads('{"name":"P"}')
    print(obj['name'])
    P
  • C#: Newtonsoft.Json.JsonConvert.DeserializeObject<T> или System.Text.Json.JsonSerializer.Deserialize<T>. Поддержка generics и атрибутов для настройки. Пример:
    var json = "{\"x\":10}";
    var obj = JsonConvert.DeserializeObject<Dictionary<string,int>>(json);
    Console.WriteLine(obj["x"]);
    10
  • Go: json.Unmarshal. Требует экспортируемых полей (с заглавной буквы) и тегов struct для маппинга. Пример:
    type User struct {Name string `json:"name"`}
    var u User
    json.Unmarshal([]byte(`{"name":"G"}`), &u)
    fmt.Println(u.Name)
    G
  • PHP: json_decode. Возвращает ассоциативный массив или объект; для строгих типов используются кастомные мапперы или Symfony Serializer.
    $o = json_decode('{"n":"x"}', true);
    print_r($o['n']);
    x
  • Kotlin: может использовать Jackson (тот же API) или kotlinx.serialization с собственными аннотациями; для data class десериализация обычно проще за счет синтаксиса языка.
  • Lua: библиотеки типа cjson с функцией decode, простая динамическая структура.
  • SQL: в СУБД (PostgreSQL) имеются функции для разбора JSON, например jsonb_to_record и операторы доступа, но это не десериализация в объекты JVM.

Отличия от Java/Jackson: статическая типизация Java требует описания целевого типа, что улучшает безопасность, но добавляет сложность при параметризованных типах. В языках с динамической типизацией (JS, Python, PHP) десериализация проще, но проверки типов требуется выполнять отдельно.

Типичные ошибки при использовании и примеры

Ниже перечислены распространённые проблемы с примерами и типичным выводом исключения.

1) Синтаксическая ошибка JSON

String json = "{name: 'Bad'}"; // кавычки не по стандарту
mapper.readValue(json, Object.class);
com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'name' (а далее стек)

2) Неизвестное свойство в JSON при строгой конфигурации

public class A { public String known; }
String json = "{\"known\":\"v\",\"x\":1}";
mapper.readValue(json, A.class);
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "x" (а далее стек)

Решение: отключение правила mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) или добавление @JsonIgnoreProperties(ignoreUnknown = true).

3) Несоответствие ожидаемого типа (MismatchedInputException)

String json = "{\"a\":1}"; // объект
List<Integer> list = mapper.readValue(json, new TypeReference<List<Integer>>(){});
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.ArrayList` out of START_OBJECT token

4) Отсутствие конструктора без аргументов или неподходящие аннотации

public class NoDefault { private final String x; public NoDefault(String x) { this.x = x; }}
mapper.readValue("{\"x\":\"v\"}", NoDefault.class);
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `NoDefault` (no Creators, like default constructor)

Решение: добавить публичный конструктор без аргументов, использовать @JsonCreator и @JsonProperty или модуль для record/constructor-инъекции.

5) Потоковые проблемы и частичная буферизация

byte[] buf = new byte[1024];
int read = in.read(buf);
mapper.readValue(buf, 0, read, MyType.class);
Возможны ошибки при указании неверного смещения/длины или при неполном JSON: JsonParseException/EOFException

Изменения в поведении и новых возможностях в последних релизах

В последних версиях Jackson происходило постепенное расширение возможностей десериализации: добавлена и улучшена поддержка Java records, расширены возможности для sealed классов и улучшена работа с параметризованными типами через JavaType и TypeFactory. Появились улучшения в десериализации дат и времени, а также опции для более гибкой конфигурации десериализаторов.

Также в новых версиях усилены проверки безопасности парсинга (например, контроль разрешённых типов при полиморфной десериализации) и добавлены дополнительные опции конфигурации для ObjectReader/ObjectWriter. При обновлении рекомендуется сверять release notes конкретной версии библиотеки, так как детали поведения и рекомендованные подходы могли измениться.

Расширенные и редкие сценарии применения

Ниже приведены более сложные примеры с пояснениями.

1) Потоковая десериализация множества объектов (NDJSON - newline-delimited JSON)

Пример java
String ndjson = "{\"id\":1}\n{\"id\":2}\n";
MappingIterator<Item> it = mapper.readerFor(Item.class).readValues(ndjson);
while (it.hasNext()) {
    Item itObj = it.next();
    System.out.println(itObj.id);
}
1
2

2) Обновление существующего объекта (merge)

Пример java
User target = new User();
target.name = "Old";
String json = "{\"age\":40}";
mapper.readerForUpdating(target).readValue(json);
System.out.println(target.name + ", " + target.age);
Old, 40

Пояснение: readerForUpdating не перезаписывает поля, отсутствующие в JSON.

3) Десериализация с использованием JavaType для сложных generic-типов

Пример java
JavaType type = mapper.getTypeFactory().constructCollectionType(List.class,
        mapper.getTypeFactory().constructParametricType(Result.class, User.class));
List<Result<User>> res = mapper.readValue(json, type);
Список объектов Result<User> (в зависимости от входа)

4) Полиморфная десериализация с использованием @JsonTypeInfo

Пример java
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes({@JsonSubTypes.Type(value = A.class, name = "a"), @JsonSubTypes.Type(value = B.class, name = "b")})
public abstract class Base {}

String json = "{\"type\":\"a\",\"field\":1}";
Base b = mapper.readValue(json, Base.class);
System.out.println(b.getClass().getSimpleName());
A

5) Использование собственного десериализатора для нестандартного формата

Пример java
public class EpochDateDeserializer extends StdDeserializer<Date> {
    public EpochDateDeserializer() { super(Date.class); }
    @Override
    public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        long epoch = p.getLongValue();
        return new Date(epoch * 1000L);
    }
}

SimpleModule mod = new SimpleModule();
mod.addDeserializer(Date.class, new EpochDateDeserializer());
mapper.registerModule(mod);
Date d = mapper.readValue("1620000000", Date.class);
System.out.println(d);
Дата, соответствующая epoch в секундах

6) Десериализация Java record

Пример java
public record Point(int x, int y) {}
String json = "{\"x\":10,\"y\":20}";
Point p = mapper.readValue(json, Point.class);
System.out.println(p);
Point[x=10, y=20]

7) Чтение при частичной буферизации (например, при чтении по сети с предварительным заголовком)

Пример java
byte[] buffer = new byte[4096];
int header = in.read(buffer, 0, 128); // прочитан заголовок
int jsonLen = in.read(buffer, 128, 512); // прочитана JSON часть
MyType obj = mapper.readValue(buffer, 128, jsonLen, MyType.class);
MyType объект (при корректном JSON)

8) Инъекция зависимостей и использование InjectableValues

Пример java
mapper.setInjectableValues(new InjectableValues.Std().addValue("now", Instant.now()));
public class C { @JacksonInject("now") public Instant now; }
C c = mapper.readValue("{}", C.class);
System.out.println(c.now);
Текущее время, переданное через InjectableValues

Эти примеры демонстрируют гибкость ObjectMapper.readValue: метод работает в простых и сложных сценариях, от потоковой десериализации до полиморфизма и пользовательских десериализаторов.

джава ObjectMapper.readValue function comments

En
ObjectMapper.readValue Deserializes JSON content from given JSON content string into a Java object