【问题标题】:moshi custom qualifier annotation to serialise null on one property onlymoshi 自定义限定符注释仅在一个属性上序列化 null
【发布时间】:2019-02-14 17:11:15
【问题描述】:

我只想为我的 JSON 正文中正在进行 PUT 的一个属性序列化 null。我不想为对象中的任何其他类型序列化 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 字段。例如

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

Json 看起来像这样:

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

当 otherCollege 为空时,对象中省略了姓氏,因为默认情况下 moshi 不会序列化我想要的空值,但限定符字段应使用空值序列化

我尝试过使用

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

标签: kotlin gson retrofit moshi


【解决方案1】:

你的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 support in Moshi 来避免@field: 奇怪。

【讨论】:

  • 这对我有用,但我注意到一个副作用是,如果你有嵌套对象并且你添加 @SerializeNulls 到它,它不仅会将该对象序列化为 null 如果它没有设置也会序列化嵌套对象内的所有空字段。是否有可能让它只在父级工作,并将嵌套对象中的字段单独保留?
  • 我创建了这个问题,它可能会更清楚地显示我遇到的问题。我认为问题在于,一旦将适配器设置为serializeNulls(),对于该节点中的其余对象,它仍然设置为该值。 stackoverflow.com/questions/67713856/…
【解决方案2】:

从我的要点尝试方法:

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

在我的例子中,我将 NULL 从 JSON 转换为默认的双精度/整数值。您可以轻松修改该方法并使其适用于您的特定情况。

附言它的 JAVA,首先将其转换为 Kotlin。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2014-11-28
  • 2018-11-17
  • 2013-09-02
  • 2015-07-27
  • 1970-01-01
  • 1970-01-01
  • 2017-03-05
  • 2021-08-15
相关资源
最近更新 更多