Gson игнорирует пользовательские значения @SerializedName для перечисления при сериализации - PullRequest
0 голосов
/ 03 мая 2019

У меня есть такие перечисления:

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 Ответ

1 голос
/ 04 мая 2019

Это происходит потому, что 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())
...