Аннотация настраиваемого квалификатора moshi для сериализации null только для одного свойства

Я хотел бы сериализовать null только для одного свойства в моем теле JSON, которое выполняется PUT. Я не хочу сериализовать null для любых других типов объекта. Класс модели такой

@Parcel
class User @ParcelConstructor constructor(var college: College?,
                                          var firstname: String?,
                                          var lastname: String?,
                                          var email: String?,
                                          var active: Boolean = true,
                                          var updatedAt: String?,
                                          var gender: String?,
                                          var picture: String?,
                                          var id: String?,
                                          @field: [CollegeField] var collegeInput: String?,
                                          @field: [CollegeField] var otherCollege: String?,)

Я хочу сериализовать поля CollegeInput и otherCollege только в том случае, если любое из них имеет значение NULL. Например

val user = User(firstname = "foo", lastname=null, collegeInput="abcd", otherCollege = null)

Json будет выглядеть примерно так:

{"user":{
  "firstname": "foo",
  "collegeInput": "abcd",
  "otherCollege": null
}}

Если otherCollege имеет значение null, lastname не указывается в объекте, поскольку по умолчанию moshi не сериализует значения NULL, что я хочу, но поля квалификаторов должны быть сериализованы с нулевыми значениями.

Я пробовал использовать

class UserAdapter {
@FromJson
@CollegeField
@Throws(Exception::class)
fun fromJson(reader: JsonReader): String? {
    return when (reader.peek()) {
        JsonReader.Token.NULL ->
            reader.nextNull()
        JsonReader.Token.STRING -> reader.nextString()
        else -> {
            reader.skipValue() // or throw
            null
        }
    }
}

@ToJson
@Throws(IOException::class)
fun toJson(@CollegeField b: String?): String? {
    return b
}


@Retention(AnnotationRetention.RUNTIME)
@JsonQualifier
annotation class CollegeField

Я добавил адаптер в moshi, но он никогда не вызывается

@Provides
@Singleton
fun provideMoshi(): Moshi {
    return Moshi.Builder()
            .add(UserAdapter())
            .build()
}

@Provides
@Singleton
fun provideRetrofit(client: OkHttpClient, moshi: Moshi, apiConfig: ApiConfig): Retrofit {
    return Retrofit.Builder()
            .baseUrl(apiConfig.baseUrl)
            .client(client)
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .addConverterFactory(ScalarsConverterFactory.create())
            .addConverterFactory(MoshiConverterFactory.create(moshi))
            .build()
}

Почему ваш метод toJson принимает только один параметр вместо всего объекта User, а fromJson возвращает String, а не User?

Praytic 10.09.2018 13:38
6
1
3 463
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Попробуйте подход из моей сути:

https://gist.github.com/OleksandrKucherenko/ffb2126d37778b88fca3774f1666ce66

В моем случае я конвертирую NULL из JSON в двойное / целочисленное значение по умолчанию. Вы можете легко изменить подход и заставить его работать в вашем конкретном случае.

p.s. его JAVA, сначала конвертируйте его в Kotlin.

для сборки релиза с включенным прогардом не забудьте применить специальные правила Moshi, plus.google.com/u/0/+OleksandrKucherenko/posts/1wLwv728FgF

Oleksandr Kucherenko 10.09.2018 14:18

проверим и сообщу вам

Jaskaran Singh 10.09.2018 15:48

Я пробовал подход, представленный здесь github.com/square/moshi. Адаптеры альтернативного типа с @JsonQualifier

Jaskaran Singh 10.09.2018 15:50
Ответ принят как подходящий

Ваш метод адаптера toJson вернет значение NULL, если квалифицированное строковое значение равно NULL, и JsonWriter не будет записывать значение NULL.

Вот квалификатор и фабрика адаптеров для установки, которые будут работать.

@Retention(RUNTIME)
@JsonQualifier
public @interface SerializeNulls {
  JsonAdapter.Factory JSON_ADAPTER_FACTORY = new JsonAdapter.Factory() {
    @Nullable @Override
    public JsonAdapter<?> create(Type type, Set<? extends Annotation> annotations, Moshi moshi) {
      Set<? extends Annotation> nextAnnotations =
          Types.nextAnnotations(annotations, SerializeNulls.class);
      if (nextAnnotations == null) {
        return null;
      }
      return moshi.nextAdapter(this, type, nextAnnotations).serializeNulls();
    }
  };
}

Теперь пройдет следующее.

class User(
  var firstname: String?,
  var lastname: String?,
  @SerializeNulls var collegeInput: String?,
  @SerializeNulls var otherCollege: String?
)

@Test fun serializeNullsQualifier() {
  val moshi = Moshi.Builder()
      .add(SerializeNulls.JSON_ADAPTER_FACTORY)
      .add(KotlinJsonAdapterFactory())
      .build()
  val userAdapter = moshi.adapter(User::class.java)
  val user = User(
      firstname = "foo",
      lastname = null,
      collegeInput = "abcd",
      otherCollege = null
  )
  assertThat(
      userAdapter.toJson(user)
  ).isEqualTo(
      """{"firstname":"foo","collegeInput":"abcd","otherCollege":null}"""
  )
}

Обратите внимание, что вы должны использовать Поддержка Kotlin в Moshi, чтобы избежать странностей @field:.

Это работает для меня, но я заметил, что побочный эффект заключается в том, что если у вас есть вложенные объекты и вы добавляете к нему @SerializeNulls, он не только сериализует этот объект до нуля, если он не установлен, также сериализует все нулевые поля внутри вложенного объекта. . Можно ли заставить это работать только на родительском уровне и оставить только поля внутри вложенного объекта?

Bueno 26.05.2021 19:25

Я создал эту проблему, которая может более четко показать, с чем я сталкиваюсь. Я думаю, проблема в том, что после того, как адаптер настроен на serializeNulls(), он остается установленным для остальных объектов в этом узле. stackoverflow.com/questions/67713856/…

Bueno 27.05.2021 14:47

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