对于序列化时的枚举,Gson忽略了自定义@SerializedName值,

时间:2019-05-03 19:43:13

标签: android kotlin gson retrofit2

我有这样的枚举:

enum class NewTaskState(val value: Int) {

    @SerializedName("0")
    STATE_INSTALLED(0),

    @SerializedName("1")
    STATE_LAUNCHED(1)

}

具有改进功能的API调用:

 @POST("tasks/android/{id}/state/update/")
 @FormUrlEncoded
 fun updateAppTaskState(
     @Path("id") id: Long,
     @Query("device_pk") deviceId: Long,
     @Field("new_state") newState: NewTaskState
 ): Single<Response<Any>>

和GSON配置:

return GsonBuilder()
    .registerTypeAdapter(Date::class.java, DateDeserializer())
    .enableComplexMapKeySerialization()
    .create()

Gson版本为2.8.5

使用此通话时,我会在日志中看到:

I/OkHttp: --> POST <removed>/tasks/android/1/state/update/?device_pk=8
I/OkHttp: Content-Type: application/x-www-form-urlencoded
I/OkHttp: Content-Length: 25
I/OkHttp: Authorization: Token <removed>
I/OkHttp: new_state=STATE_INSTALLED

因此,它忽略序列化上的@SerializedName值,但在反序列化上运行良好。

怎么了?

1 个答案:

答案 0 :(得分:1)

发生这种情况是因为Gson不参与url表单编码。

来自@Field的javadoc:

  

使用Retrofit.stringConverter(Type, Annotation[])(或Object.toString(),如果未安装匹配的字符串转换器)将值转换为字符串,然后形成URL编码。 null个值将被忽略。传递List或数组将为每个非null项目产生一个字段对。

并且GsonConverterFactory不会覆盖Converter.Factory#stringConverter,因此它不会忽略任何内容。只是不参加


作为解决方法,您可以执行类似的操作:

Converter

object EnumAsOrdinalToStringConverter : Converter<Enum<*>, String> {
    override fun convert(value: Enum<*>): String =
            value.ordinal.toString()
}

Factory

class EnumAsOrdinalToStringConverterFactory : Converter.Factory() {
    override fun stringConverter(
            type: Type,
            annotations: Array<Annotation>,
            retrofit: Retrofit
    ): Converter<*, String>? = if (type is Class<*> && type.isEnum) {
        EnumAsOrdinalToStringConverter
    } else {
        null
    }
}

建筑物Retrofit

addConverterFactory(EnumAsOrdinalToStringConverterFactory())