Kotlin默认参数未随Retrofit请求体传递的问题排查与解决
问题描述
使用kotlinx.serialization的@Serializable注解定义了如下Request数据类:
@Serializable data class Request( val a: String, val b: String, val c: String = "version" )
在Retrofit接口及调用代码中:
@PUT(value = "path/to/endpoint") suspend fun sendRequest(@Body request: Request): Response override fun sendRequest(request: Request) = flow<Resource<Response, NetworkError>> { emit(Resource.Success(network.sendRequest(request))) }.catch { emit(Resource.Error(it.parseNetworkError())) }
发现默认参数val c: String = "version"不会被包含在请求体中,但显式传入该参数(如Request("test", "test", "version"))或在发送前断点调试时,该参数能正常随请求体传递。而使用Request("test", "test")创建实例则不行。请问这是否是编译器优化导致的?该如何避免这种情况?
原因与解决方案
原因
这不是编译器优化的问题,而是kotlinx.serialization的默认序列化规则导致的:
- Kotlin数据类的默认参数在未显式赋值时,仅会在类内部使用默认值,但不会被kotlinx.serialization判定为已初始化的属性。
- 序列化器默认仅序列化显式赋值的属性,未显式传入的默认参数会被跳过,不会生成对应的请求体字段。
解决方案
可以通过以下几种方式解决:
添加
@Required注解强制序列化
给默认参数加上@Required注解,让序列化器强制包含该属性,哪怕它使用了默认值(需kotlinx.serialization 1.3及以上版本支持):@Serializable data class Request( val a: String, val b: String, @Required val c: String = "version" )开启序列化器的
encodeDefaults配置
创建Json序列化器时开启encodeDefaults选项,这样所有带默认值的属性都会被序列化,无论是否显式赋值:val json = Json { encodeDefaults = true }配合Retrofit使用时,需要在构建实例时指定这个自定义的Json转换器:
Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(json.asConverterFactory("application/json".toMediaType())) .build()构造时显式传入默认值
创建Request实例时始终显式传入c的默认值,或者添加工厂方法统一处理:// 方式1:直接显式传参 val request = Request("test", "test", "version") // 方式2:添加工厂方法 @Serializable data class Request( val a: String, val b: String, val c: String ) { companion object { fun create(a: String, b: String) = Request(a, b, "version") } }
内容的提问来源于stack exchange,提问作者nilsi
相关产品推荐
相关产品推荐

