Укажите поля класса для сериализации в JSON в Ktor

Обслуживание содержимого JSON в Ktor, как описано в HTTP API — быстрый старт — Ktor, как показано в примерах, работает для обычных коллекций (списков, карт и т. д.) и классов данных. Однако, если я хочу сериализовать класс, который не является классом данных и имеет поля, которые я хочу исключить, как мне указать поля, которые нужно сериализовать, и их сериализованные имена? Предположим, что я использую Gson, могу ли я сделать это так же, как сериализовать объект класса, используя Gson напрямую?


person Shreck Ye    schedule 15.06.2019    source источник
comment
Используйте gson api, как обычно. Классы без данных должны работать нормально. Вы также можете просто попробовать это. Если вам нужна дополнительная помощь, задайте более конкретный вопрос.   -  person avolkmann    schedule 16.06.2019


Ответы (1)


Насколько мне известно, используя Gson, у вас есть несколько вариантов.

<сильный>1. Использование перехода

Если вы пометите поле @Transient (transient в Java), оно будет исключено из сериализации:

data class Foo(
    @Transient val a: Int,
    val b: Int)

Здесь b будет сериализован, а a — нет.

У этого есть огромный недостаток — почти каждый фреймворк в java учитывает @Transient, и иногда вы не хотите, чтобы Gson сериализовал его, но вы можете захотеть, например, сохранить его в базе данных (если вы будете использовать один и тот же класс для обоих). Чтобы учесть это, есть еще один вариант, использующий @Expose.

<сильный>2. Использование экспозиции

Вам нужно создать экземпляр gson с помощью компоновщика:

val gson = GsonBuilder()
    .excludeFieldsWithoutExposeAnnotation()
    .create();

Теперь поля без @Expose не будут сериализованы:

data class Foo(
    val a: Int,
    @Expose val b: Int)

Опять же, a не будет сериализован, а b будет.

<сильный>3. Использование стратегий исключения

Более продвинутым методом является использование стратегий исключения. Это позволяет проводить множество самоанализов на полях. От пользовательских аннотаций до имени или типа поля.

Опять же, вам нужно создать gson с помощью компоновщика:

val gson = GsonBuilder()
    .addSerializationExclusionStrategy(strategyInstance)
    .create();

И вы определяете стратегию как:

object : ExclusionStrategy() {
  override fun shouldSkipField(field: FieldAttributes): Boolean {
  }

  override fun shouldSkipClass(clazz: Class<*>): Boolean {
  }
}

внутри shouldSkipField вы возвращаете true, когда вы не хотите сериализовать поле, и false, когда вы это делаете. Поскольку он получает FieldAttributes, вы можете получить множество свойств из поля, таких как имя и аннотации. Это позволяет осуществлять очень тонкий контроль.

Наконец, вы можете установить эту стратегию и для десериализации, и для обоих — addDeserializationExclusionStrategy и setExclusionStrategies.

person Fred    schedule 17.06.2019
comment
Стоит отметить, что ktor передает GsonBuilder в качестве получателя в блоке gson: install(ContentNegotiation) { gson { // Configure GsonBuilder here } } - person avolkmann; 17.06.2019
comment
Так что я также могу просто использовать @SerializedName, чтобы указать сериализованное имя JSON, верно? - person Shreck Ye; 18.06.2019
comment
да. На самом деле в приложениях для Android мы всегда так делаем, потому что имя переменной обычно запутывается, а затем сериализованный json полностью ломается. Я не думаю, что вы делаете это в Backend, но это все равно удобно, если вы хотите другое имя. - person Fred; 18.06.2019