Быстрый парсинг JSON в Java с новыми правилами безопасности в Fastjson2

Если вы работаете с Java больше пяти лет, название Fastjson наверняка вызывает у вас смешанные чувства. С одной стороны, библиотека действительно работала быстрее Jackson. С другой — регулярные уязвимости с десериализацией через AutoType превратили её использование в постоянный головную боль для специалистов по безопасности.
В команде Alibaba эти проблемы знали лучше других. Два года назад они фактически переписали библиотеку с нуля. Встречайте Fastjson2: переосмысленный движок для работы с JSON, где за основу взяли безопасность и производительность на современных версиях Java.
Как изменилась безопасность
Главный грех первой версии заключался в механизме AutoType. Он мог создавать произвольные Java-объекты из JSON-полезной нагрузки прямо во время парсинга. Злоумышленники регулярно находили способы обойти встроенный список заблокированных классов и вызывать RCE.
В Fastjson2 подход изменили кардинально. AutoType теперь выключен по умолчанию, а сканирование классов работает без жёстко зашитых белых списков. Появился режим SafeMode, который полностью запрещает автоматическую сборку произвольных объектов.
Все флаги конфигурации по умолчанию перевели в состояние OFF. Библиотека больше не пытается угадывать типы там, где это может навредить.
Основные возможности
Разработчики ориентировались на современные версии JDK, начиная с Java 8 и заканчивая Java 21. Движок оптимизирован под использование Vector API, работу с типами Record и компактными строками.
Вот что выделяется при знакомстве с библиотекой:
- Двухформатность. Поддержка обычного текстового JSON и бинарного протокола JSONB.
- Быстрый выборочный парсинг через JSONPath без создания промежуточных Java-объектов.
- Модули расширения для Kotlin с удобным DSL и полная поддержка Spring Framework версий 5 и 6.
- Нативная сборка с GraalVM Native Image из коробки.
Быстрый старт в коде
Подключение библиотеки состоит из добавления одной зависимости в pom.xml:
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.61</version>
</dependency>
Простой пример парсинга и сериализации выглядит знакомо:
import com.alibaba.fastjson2.JSON;
// Парсинг строки в объект
User user = JSON.parseObject("{\"name\":\"John\",\"age\":25}", User.class);
// Сериализация объекта в JSON
String json = JSON.toJSONString(user);
Если вы пишете на Kotlin, модуль fastjson2-kotlin предлагает лаконичные расширения. Код получается заметно cleaner за счёт функции-расширения to<T>():
import com.alibaba.fastjson2.*
val text = """{"id":1,"name":"John"}"""
val user = text.to<User>()
val jsonBytes = user.toJSONByteArray()
Бинарный формат JSONB для микросервисов
Текстовый JSON остаётся стандартом для REST API, но в межсервисном взаимодействии он теряет позиции из-за избыточного размера и затрат на конвертацию строк. Fastjson2 содержит встроенную реализацию бинарного формата JSONB.
JSONB кодирует типы данных и структуру в компактный набор байтов. Это дает существенную экономию трафика и ускоряет работу RPC-сервисов.
User user = new User(1, "John");
// Сериализация в байтовый массив JSONB
byte[] bytes = JSONB.toBytes(user);
// Сериализация с дополнительным сжатием структурированных данных
byte[] compactBytes = JSONB.toBytes(user, JSONWriter.Feature.BeanToArray);
// Обратный парсинг
User parsedUser = JSONB.parseObject(bytes, User.class);
Сжатие с опцией BeanToArray превращает объект в массив значений без повторения имён полей, что приближает эффективность формата к Protobuf или Kryo.
Выборочное чтение через JSONPath
Часто из огромного JSON-ответа микросервиса нужно забрать всего одно или два поля. Классические парсеры вроде Jackson сначала выстраивают в памяти полное дерево или создают объект со всеми полями, тратя ресурсы CPU и память.
Fastjson2 решает эту задачу с помощью реализации JSONPath стандарта SQL:2016. Он умеет извлекать данные напрямую из сырого байтового потока:
byte[] payload = fetchLargeJsonFromNetwork();
// Создаём и кэшируем путь
JSONPath path = JSONPath.of("$.data.user.id");
// Извлекаем значение напрямую из байтового массива
JSONReader reader = JSONReader.of(payload);
Object userId = path.extract(reader);
Такой трюк полезен в высоконагруженных пайплайнах обработки данных, где лишние аллокации объектов в JVM сразу приводят к частым паузам Garbage Collector.
Миграция с первой версии
Договориться о полной обратной совместимости при смене мажорной версии невозможно, но авторы постарались облегчить переход. Для проектов, завязанных на старый API, создали модуль совместимости:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.61</version>
</dependency>
Он использует старый groupId и пакеты com.alibaba.fastjson, но внутри работает на новом движке v2. Это дает возможность обновиться без переписывания сотен импортов в legacy-коде.
Однако при переходе нужно учитывать важные изменения:
- Разбор циклических ссылок отключен по умолчанию.
- Умное сопоставление полей (Smart Match) больше не работает из коробки.
- Все опции сериализатора нужно включать явно через
JSONWriter.Feature.
Fastjson2 получился взрослым и зрелым продуктом. Разработчики проделали работу над ошибками, избавились от опасных настроек по умолчанию и дали Java-экосистеме действительно быстрый инструмент.
Попробовать Fastjson2 однозначно стоит, если вы развиваете высоконагруженные сервисы, работаете со Spring 6 / GraalVM Native Image или ищете альтернативу тяжелым форматам сериализации в Kotlin-проектах.
