Аналог STRICT_DUPLICATE_DETECTION в Гсоне - PullRequest
0 голосов
/ 17 декабря 2018

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

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

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

{"x": true, "x": false} 

1 Ответ

0 голосов
/ 18 декабря 2018

Вроде.По какой-то причине 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.

...