Можем ли мы полагаться на способность Gson изменять атрибуты val? - PullRequest
0 голосов
/ 02 февраля 2019

Атрибуты val Котлина, по замыслу, неизменны.Они должны быть фиксированными и неизменяемыми после инициализации.

Однако я случайно обнаружил, что Gson может изменять эти атрибуты.

Рассмотрим этот пример:

//Entity class:
class User {
    val name: String = ""
    val age: Int = 0
}

Поскольку name и age определены как val и инициализируются пустой строкой и нулем, они должны оставаться неизменными и никогда не изменяться.

Однако этот тест завершается успешно:

fun main() {
    val json = "{\"name\":\"Mousa\",\"age\":30}"
    val user = Gson().fromJson<User>(json, User::class.java)
    assert(user.name == "Mousa")
    assert(user.age == 30)
    print("Success")
}

Использование этой функции делает код чище.Потому что эти атрибуты изменены Gson и не могут быть изменены остальной частью нашего кода.В противном случае мне нужно предоставить некоторые изменяемые поля поддержки для Gson и некоторые неизменяемые атрибуты для остальной части кода.

Я не знаю, является ли это «функцией» из Gson или «ошибкой»,Поэтому мой вопрос: можем ли мы полагаться на это, или это поведение может измениться позже?

1 Ответ

0 голосов
/ 02 февраля 2019

Если вы запустите javap -p User.class, вы получите следующий вывод:

public final class q54491286.User {
    private final java.lang.String name;
    private final int age;
    public final java.lang.String getName();
    public final int getAge();
    public q54491286.User();
}

Неизменность Kotlin поддерживается никакими методами-мутаторами, сгенерированными для полей, которые (неявно) объявлены private и final.Если вы не определили адаптер пользовательского типа, Gson по своему дизайну не использует ни аксессоры, ни мутаторы во время сериализации и десериализации соответственно по проекту для классов объектов простых данных (подробнее здесь в Использование полей против геттеров для обозначения элементов Json раздел).Кроме того, Gson может модифицировать final поля, и это тоже выбор дизайна.

Из-за интенсивного использования отражения неизменяемость - довольно относительная вещь в Java.Например, я могу легко изменить неизменяемую (по замыслу) строку, используя отражение, делая ее своего рода изменяемой ( намерения ):

final String s = "foo";
final Field valueField = String.class.getDeclaredField("value");
valueField.setAccessible(true);
valueField.set(s, new char[]{ 'b', 'a', 'r' });
System.out.println(s);

Это приводит к bar при использовании моегоjava от java version "1.8.0_191".Нет неизменности, хе-хе.

С другой стороны, если ваш класс может быть обнаружен методом переопределения стратегий адаптеров типа Gson универсальным способом (Gson запрещает переопределять адаптеры типа Object и JsonElement), вы сможете написать собственный десериализатор, который запрещает сгенерированным Kotlin классам (обнаруженным аннотацией kotlin.Metadata) иметь десериализованные поля только для чтения (хотя и не уверен, что он имеет преимущество).Или просто внедрите десериализатор, который будет сканировать поток / дерево JSON на предмет полей, не предназначенных только для чтения, и использовать их только при создании нового объекта User с его легальным конструктором, не использующим отражение.

Iне знаю, является ли это «особенностью» Gson или «ошибкой».

Подводя итог, это особенность.

Итак, мой вопрос:Можем ли мы полагаться на это, или это поведение может измениться позже?

Это, скорее всего, никогда не изменится в Gson 2.x.Насколько я знаю, никаких планов по выпуску серьезного обновления, Gson 3.x и т. Д. Нет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...