Retrofit POST发送自定义对象数组如何序列化无类名标准JSON
问题根因
该问题和Gson配置无关。使用@FormUrlEncoded搭配@Field传参时,Retrofit默认会直接调用参数对象的toString()方法生成表单字段值,Kotlin data class默认的toString()实现输出就是带类名、属性键值对的格式,不会走Gson序列化流程,因此才会输出带类名的非标准格式。
解决方案
根据后端接口的格式要求,二选一即可:
方案1:保留表单提交格式,手动序列化JSON(推荐,适配当前接口要求)
不需要修改接口的application/x-www-form-urlencoded表单提交逻辑,只需要提前用Gson将列表对象序列化为标准JSON字符串,再传入@Field参数即可。
- 调整Retrofit接口定义,将
diff参数类型改为String:
@FormUrlEncoded @POST("/patch") suspend fun insertTracks( @Field("diff") diff: String ): PlaylistResponse
- 发起请求前,手动用Gson序列化对象:
// 建议全局复用单例Gson实例,不要每次新建 val gson = Gson() val operationList = listOf( PlaylistInsertOperation( tracks = listOf( TrackId(id = "39117009", albumId = "5034819"), TrackId(id = "89341636", albumId = "18635889") ) ) ) // 序列化为标准JSON字符串 val diffJson = gson.toJson(operationList) // 发起请求 api.insertTracks(diffJson)
该方案生成的请求参数完全符合接口要求:diff=[{"tracks":[{"id":"39117009","albumId":"5034819"},...]}]
方案2:改用JSON请求体(需后端支持)
如果后端接口支持接收application/json格式的请求体,可以去掉@FormUrlEncoded注解,直接用@Body传递对象,Retrofit会自动调用Gson完成序列化:
// 定义请求体结构 data class InsertTracksRequest( val diff: List<PlaylistInsertOperation> ) @POST("/patch") suspend fun insertTracks( @Body request: InsertTracksRequest ): PlaylistResponse
注意:该方案的请求体为纯JSON格式,和原表单提交格式差异较大,必须提前确认后端支持后再使用。
注意事项
给出的接口示例中albumId字段为数字类型,但当前TrackId定义中albumId为String类型,序列化后会带双引号变成字符串。如果接口要求数字类型,需要将TrackId的albumId字段类型修改为Long,避免参数类型校验失败。
内容的提问来源于stack exchange,提问作者Viewed
相关产品推荐
相关产品推荐

