Android @FormUrlEncoded@Field枚举未使用自定义Moshi适配器
我在我的应用程序中使用改型(v2.9.0)和Moshi(v1.11.0)。我尝试以这种方式调用端点:Android @FormUrlEncoded@Field枚举未使用自定义Moshi适配器,android,json,enums,retrofit,moshi,Android,Json,Enums,Retrofit,Moshi,我在我的应用程序中使用改型(v2.9.0)和Moshi(v1.11.0)。我尝试以这种方式调用端点: @FormUrlEncoded @PATCH("anime/{anime_id}/my_list_status") fun updateListStatus( @Path("anime_id") animeId: Long, @Field("num_watched_episodes") nbWatchedEpisodes
@FormUrlEncoded
@PATCH("anime/{anime_id}/my_list_status")
fun updateListStatus(
@Path("anime_id") animeId: Long,
@Field("num_watched_episodes") nbWatchedEpisodes: Int,
@Field("score") score: Double,
@Field("status") watchStatus: WatchStatus,
): Single<MyListStatus>
Moshi.Builder()
.addLast(KotlinJsonAdapterFactory())
.add(AnimeMoshiAdapters())
.build()
我创建了一个自定义适配器,因为我的应用程序使用大写枚举名,而后端使用小写名称:
class AnimeMoshiAdapters {
/* Others adapters */
@ToJson
fun watchStatusToJson(watchStatus: WatchStatus): String =
watchStatus.toString().toLowerCase(Locale.getDefault())
@FromJson
fun watchStatusFromJson(watchStatus: String): WatchStatus =
WatchStatus.valueOf(watchStatus.toUpperCase(Locale.getDefault()))
}
我通过以下方式创建我的Moshi实例:
@FormUrlEncoded
@PATCH("anime/{anime_id}/my_list_status")
fun updateListStatus(
@Path("anime_id") animeId: Long,
@Field("num_watched_episodes") nbWatchedEpisodes: Int,
@Field("score") score: Double,
@Field("status") watchStatus: WatchStatus,
): Single<MyListStatus>
Moshi.Builder()
.addLast(KotlinJsonAdapterFactory())
.add(AnimeMoshiAdapters())
.build()
我的改造实例使用它(使用Koin注入):
reformation.Builder()
.baseUrl(获取(命名为(“baseUrl”))
.client(获取(命名为(“默认”))
.addConverterFactory(MoshiConverterFactory.create(get())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
解析Json以创建WatchStatus枚举时,将使用适配器。这是显而易见的,因为如果我删除自定义适配器,调用将失败,并出现错误“com.squareup.moshi.JsonDataException:预期为[COMPLETED,droped,ON_HOLD,PLAN_TO_WATCH,WATCHING]”。
当我尝试调用上面指定的端点时,Json中WatchStatus的转换是错误的,枚举名保持大写,这意味着没有使用我的自定义适配器。如果我查看改装日志,我可以看到它发送“num_wasted_stitues=12&score=6.0&status=ON_HOLD”,因此状态不会转换为小写
如果我尝试使用相同的Moshi实例手动转换Json中的WatchStatus,它将按预期工作,因此我相信我的自定义适配器实现是正确的
如何在此调用中使用自定义Moshi适配器进行改装?Moshi适配器的
toJson
应用于改装请求的主体(=用@body
注释的参数),而不是查询参数(=用@FIELD
注释的参数)。这是正确的和预期的行为,因为查询参数按标准不应是JSON格式的字符串(尽管在您的例子中它只是一个字符串)。如果您的服务器希望status
字段作为查询参数,那么除了自己提供小写字段外,没有其他方法:
@FormUrlEncoded
@PATCH("anime/{anime_id}/my_list_status")
fun updateListStatus(
...
@Field("status") watchStatus: String
): Single<MyListStatus>
如果您对服务器的实现没有影响,那么跳过本文的其余部分
如果要利用自定义适配器的toJson
函数,服务器需要更改请求以接受JSON正文而不是查询参数,如下所示:
PUT: anime/{anime_id}/my_list_status
BODY:
{
"anime_id" : Long,
"num_watched_episodes" : Int,
"score" : Double,
"status" : WatchStatus
}
然后,您将为主体创建一个数据类,例如命名为RequestBody
,然后您可以将请求更改为:
@PUT("anime/{anime_id}/my_list_status")
fun updateListStatus(
...
@BODY body: RequestBody
): Single<MyListStatus>
@PUT(“动画/{anime\u id}/my\u list\u status”)
趣味updateListStatus(
...
@主体:请求主体
):单身
在这种情况下,您的自定义适配器将生效,并通过其定义的
toJson
逻辑来转换RequestBody
中的WatchStatus
。感谢您的解释,这完全有意义。为了将jsonWatchStatus解析保持在一个地方,我在我的存储库中重用了Moshi适配器:AnimeMoshiAdapters().watchStatusToJson(listStatus.status),它可以按需要工作。
@PUT("anime/{anime_id}/my_list_status")
fun updateListStatus(
...
@BODY body: RequestBody
): Single<MyListStatus>