You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Retrofit反序列化JSON报错:缺失类鉴别器的多态序列化器未找到

问题:Kotlin+Retrofit POST请求触发多态序列化异常(未使用多态)

异常信息

kotlinx.serialization.json.internal.JsonDecodingException: Polymorphic serializer was not found for missing class discriminator ('null')

接口返回JSON

{"CustID":101,"DeviceID":81}

相关代码实现

数据类

@SerialName("NewCustVals")
@Serializable
data class NewCustVals (
    @SerialName("CustID")
    var CustID: Int? = 0,
    @SerialName("DeviceID")
    var DeviceID: Int? = 0
)

Retrofit服务接口

interface LTECustomerInterface {
    companion object {
        private var TAG :String = "LTECustomerInterface"
        var BASE_URL = "http://XXXXXXXXXXX:XXXX/"  //test server
        lateinit var callbackApi :ApiCallback

        @OptIn(ExperimentalSerializationApi::class)
        fun create(cb:ApiCallback): LTECustomerInterface {

            callbackApi = cb

            val retrofit = Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(Json{ignoreUnknownKeys = true; isLenient = true}.asConverterFactory( "application/json".toMediaType()))
             //   .client(client)
                .build()

            return retrofit.create(LTECustomerInterface::class.java)
        }
    }

    @POST("/newCustomer")
    suspend fun newCustomer(@Body data : Customer ) :Call<NewCustVals>
}

请求调用代码

fun sendCustomer() {
    viewModelScope.launch(Dispatchers.IO) {
       val call = serverCustomerHttpInterface.newCustomer(_currentCust.value)

           call.enqueue(object : retrofit2.Callback<NewCustVals>{
             override fun onResponse(call: Call<NewCustVals>, response: Response<NewCustVals>) {
               Log.i(TAG,"NewCustomer onResponse called")
             }

             override fun onFailure(call: Call<NewCustVals>, t: Throwable) {
               Log.i("sendCustomer()","NewCustomer onFailure")
             }
          })
    }
}

排查思路

  • 修正suspend函数返回值:Retrofit中标记为suspend的接口方法,不能返回Call<T>,需直接返回NewCustVals或Response<NewCustVals>;若要使用enqueue回调,需去掉suspend关键字,保持返回Call<NewCustVals>。当前写法会导致序列化逻辑混乱,触发非预期的多态检查。示例修改:
    @POST("/newCustomer")
    suspend fun newCustomer(@Body data : Customer ) : NewCustVals
    
  • 检查Customer类序列化配置:作为@Body参数的Customer类必须添加@Serializable注解,且内部无多态类型字段。若该类涉及继承,需正确配置kotlinx序列化多态规则,但根据描述应为简单数据类,先确认注解是否完整。
  • 移除类级别的@SerialName("NewCustVals"):该注解多用于多态场景标记类的鉴别器值,你的数据类直接对应返回JSON结构,无需此注解,移除可避免序列化器误判为多态类型。
  • 调整JSON转换器配置:可显式补充序列化配置,避免默认多态逻辑干扰,示例:
    Json {
        ignoreUnknownKeys = true
        isLenient = true
        explicitNulls = true
    }
    

内容的提问来源于stack exchange,提问作者userCB

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 20:27:25