Аналог STRICT_DUPLICATE_DETECTION в Gson

Я хочу предотвратить такую ​​«инъекцию json» при десериализации данных JSON. По умолчанию парсеры json не заботятся о дублированных ключах в объекте и просто перезаписывают их.

Я потратил некоторое время на то, чтобы найти функцию, обращающую это поведение вспять. Я добился успеха с Джексоном, но не с Гсоном. Проблема в том, что большая часть кода в проекте основана на Gson. Так что переключиться на Джексона непросто.

В Джексоне эта функция называется "STRICT_DUPLICATE_DETECTION"

{"x": true, "x": false} 
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
0
156
1

Ответы 1

Вроде, как бы, что-то вроде. По какой-то причине Gson обнаруживает конфликты имен при десериализации экземпляров Map, но не выполняет такую ​​проверку для пакетов данных или JsonElement и его потомков (поэтому вы не можете написать десериализатор JSON на основе дерева для их обнаружения).

Данный,

{
    "x": true,
    "x": false
}
final class Foo {

    @SuppressWarnings("UnnecessaryBoxing")
    final boolean x = Boolean.valueOf(false);

}
final Foo foo = gson.fromJson(jsonReader, Foo.class);
if ( !foo.x ) {
    throw new AssertionError();
}

Это не подходит для стандартного JsonReader. Однако вы можете обойти это на самом низком уровне. Это немного сложно и плохо оптимизировано, но охватывает все возможные десериализаторы (и это, вероятно, объясняет, почему Gson ведет себя по-разному в разных десериализаторах: каждый такой десериализатор должен сам выполнять эту проверку и может просто пропустить задание).

final class StrictNamesJsonReader
        extends JsonReader {

    private final Stack<Set<String>> nameStack = new Stack<>();

    private Set<String> names;

    private StrictNamesJsonReader(final Reader reader) {
        super(reader);
    }

    static JsonReader of(final Reader reader) {
        return new StrictNamesJsonReader(reader);
    }

    @Override
    public void beginObject()
            throws IOException {
        super.beginObject();
        names = new HashSet<>();
        nameStack.add(names);
    }

    @Override
    public String nextName()
            throws IOException {
        final String name = super.nextName();
        if ( !names.add(name) ) {
            throw new JsonSyntaxException("Detected duplicate property name " + name + " in " + names + " at " + this);
        }
        return name;
    }

    @Override
    public void endObject()
            throws IOException {
        super.endObject();
        nameStack.pop();
        names = !nameStack.isEmpty() ? nameStack.peek() : null;
    }

}

Как видите, эта реализация JsonReader сама управляет обнаружением дубликатов имен и генерирует что-то вроде следующего исключения

Exception in thread "main" com.google.gson.JsonSyntaxException: Detected duplicate property name x in [x] at StrictNamesJsonReader at line 3 column 5 path $.x

если обнаружены дубликаты.

Однако вы можете попросить пересмотреть свой вопрос на https://github.com/google/gson/pull/649. Я действительно считаю, что десериализаторы - неправильный способ обнаружения дубликатов, и JsonReader следует улучшить в отличие от того, что предлагается в этом PR.

Другие вопросы по теме