>_ DevTrendspl

Język

Strona główna

Języki

Sekcje

Frontend Backend Mobilne DevOps AI / ML GameDev Blockchain Systemy wbudowane Bezpieczeństwo
Java

Szybkie parsowanie JSON w Javie dzięki nowym zasadom bezpieczeństwa w Fastjson2

fastjson logo

Jeśli pracujesz z Javą od ponad pięciu lat, nazwa Fastjson prawdopodobnie wzbudza w Tobie mieszane uczucia. Z jednej strony biblioteka była faktycznie szybsza niż Jackson. Z drugiej jednak, regularne luki w deserializacji poprzez AutoType zamieniały jej używanie w ciągły ból głowy dla specjalistów ds. bezpieczeństwa.

Zespół z Alibaba znał te problemy lepiej niż ktokolwiek inny. Dwa lata temu zasadniczo przepisał bibliotekę od zera. Poznaj Fastjson2: przemyślany silnik do pracy z JSON, w którym bezpieczeństwo i wydajność na nowoczesnych wersjach Javy zostały potraktowane jako fundament.

Jak zmieniło się bezpieczeństwo

Głównym grzechem pierwszej wersji był mechanizm AutoType. Pozwalał on tworzyć dowolne obiekty Java bezpośrednio z ładunku JSON podczas parsowania. Atakujący regularnie znajdowali sposoby na ominięcie wbudowanej listy zablokowanych klas i wywoływanie RCE.

W Fastjson2 podejście zmieniło się diametralnie. AutoType jest teraz domyślnie wyłączony, a skanowanie klas działa bez zakodowanych na twardo białych list. Wprowadzono SafeMode, który całkowicie zabrania automatycznego składania dowolnych obiektów.

Wszystkie flagi konfiguracyjne są teraz domyślnie ustawione na OFF. Biblioteka nie próbuje już zgadywać typów tam, gdzie mogłoby to wyrządzić szkodę.

Główne funkcje

Deweloperzy skierowali bibliotekę na nowoczesne wersje JDK, od Javy 8 do Javy 21. Silnik jest zoptymalizowany pod kątem użycia Vector API, typów Record i kompaktowych ciągów znaków.

Oto co wyróżnia się podczas zapoznawania się z biblioteką:

  • Obsługa dualnego formatu. Zarówno zwykłego tekstowego JSON, jak i binarnego protokołu JSONB.
  • Szybkie selektywne parsowanie przez JSONPath bez tworzenia pośrednich obiektów Java.
  • Moduły rozszerzeń dla Kotlina z wygodnym DSL i pełna obsługa Spring Framework w wersjach 5 i 6.
  • Kompilacja natywna z GraalVM Native Image out of the box.

Szybki start w kodzie

Dodanie biblioteki polega na włączeniu pojedynczej zależności w pom.xml:

<dependency>
    <groupId>com.alibaba.fastjson2</groupId>
    <artifactId>fastjson2</artifactId>
    <version>2.0.61</version>
</dependency>

Prosty przykład parsowania i serializacji wygląda znajomo:

import com.alibaba.fastjson2.JSON;

// Парсинг строки в объект
User user = JSON.parseObject("{\"name\":\"John\",\"age\":25}", User.class);

// Сериализация объекта в JSON
String json = JSON.toJSONString(user);

Jeśli piszesz w Kotlinie, moduł fastjson2-kotlin oferuje zwięzłe rozszerzenia. Kod wychodzi zauważalnie czystszy dzięki funkcji rozszerzającej to<T>():

import com.alibaba.fastjson2.*

val text = """{"id":1,"name":"John"}"""
val user = text.to<User>()

val jsonBytes = user.toJSONByteArray()

Binarny format JSONB dla mikroserwisów

Tekstowy JSON pozostaje standardem dla REST API, ale w komunikacji między serwisami traci grunt z powodu nadmiernego rozmiaru i narzutu konwersji ciągów znaków. Fastjson2 zawiera wbudowaną implementację binarnego formatu JSONB.

JSONB koduje typy danych i strukturę w kompaktowy zestaw bajtów. Zapewnia to znaczne oszczędności ruchu sieciowego i przyspiesza usługi 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);

Kompresja z opcją BeanToArray przekształca obiekt w tablicę wartości bez powtarzania nazw pól, przybliżając efektywność formatu do Protobuf lub Kryo.

Selektywne odczytywanie przez JSONPath

Często z ogromnej odpowiedzi JSON mikroserwisu potrzebujesz wyodrębnić tylko jedno lub dwa pola. Klasyczne parsery takie jak Jackson najpierw budują w pamięci pełne drzewo lub tworzą obiekt ze wszystkimi polami, zużywając zasoby CPU i pamięci.

Fastjson2 rozwiązuje ten problem implementacją standardu JSONPath z SQL:2016. Może wyodrębniać dane bezpośrednio ze strumienia surowych bajtów:

byte[] payload = fetchLargeJsonFromNetwork();

// Создаём и кэшируем путь
JSONPath path = JSONPath.of("$.data.user.id");

// Извлекаем значение напрямую из байтового массива
JSONReader reader = JSONReader.of(payload);
Object userId = path.extract(reader);

Ten trick jest przydatny w potokach przetwarzania danych o wysokim obciążeniu, gdzie niepotrzebne alokacje obiektów w JVM natychmiast prowadzą do częstych pauz Garbage Collectora.

Migracja z pierwszej wersji

Osiągnięcie pełnej kompatybilności wstecznej przy zmianie głównych wersji jest niemożliwe, ale autorzy starali się ułatwić przejście. Utworzono moduł kompatybilności dla projektów opierających się na starym API:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>2.0.61</version>
</dependency>

Wykorzystuje on stare pakiety groupId i com.alibaba.fastjson, ale wewnętrznie działa na nowym silniku v2. Umożliwia to aktualizację bez przepisywania setek importów w starszym kodzie.

Jednak podczas migracji należy wziąć pod uwagę ważne zmiany:

  • Parsowanie cyklicznych referencji jest domyślnie wyłączone.
  • Inteligentne dopasowanie pól nie działa już out of the box.
  • Wszystkie opcje serializatora muszą być jawnie włączone przez JSONWriter.Feature.

Fastjson2 okazał się dojrzałym i solidnym produktem. Deweloperzy wyciągnęli wnioski z przeszłych błędów, wyeliminowali niebezpieczne domyślne ustawienia i dali ekosystemowi Java naprawdę szybkie narzędzie.

Zdecydowanie wypróbuj Fastjson2, jeśli tworzysz usługi o wysokim obciążeniu, pracujesz ze Spring 6 / GraalVM Native Image lub szukasz alternatywy dla ciężkich formatów serializacji w projektach Kotlin.

Powiązane projekty