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

使用Ktor将JSON反序列化为Kotlin Map/数据类时遇转换错误

Ktor JSON反序列化报错:NoTransformationFoundException

问题描述

使用Ktor将OAuth2接口返回的JSON反序列化为Map<String, Any>或自定义数据类时,持续触发NoTransformationFoundException,提示无法完成ByteBufferChannel到目标类型的转换。

初始代码(反序列化为Map)

val beans = beans {
    bean("oauthClient") {
        HttpClient(CIO) {
            expectSuccess = true
            install(DefaultRequest){
                url("${env["oauth.url"]!!}/ms_oauth/oauth2/endpoints/oauthservice/tokens")
            }
            install(Auth) {
                basic {
                    credentials {
                        BasicAuthCredentials(username = env["client.id"]!!, password = env["client.secret"]!!)
                    }
                }
            }
            install(ContentNegotiation) {
                json()
            }
        }
    }
    bean {
        val oauthResults: Map<String,Any> = runBlocking { // 此处报错
            ref<HttpClient>("oauthClient").submitForm("${env["oauth.url"]!!}/ms_oauth/oauth2/endpoints/oauthservice/tokens",
                Parameters.build {
                    append("grant_type", "password")
                    append("scope", "bug.rest.public")
                    append("username", env["ssoUsername"]!!)
                    append("password", env["ssoPassword"]!!)
                }
            ).body()
        }
    }
}

初始错误信息

Caused by: io.ktor.client.call.NoTransformationFoundException: 
No transformation found: class io.ktor.utils.io.ByteBufferChannel -> class kotlin.collections.Map

更新尝试(反序列化为自定义数据类)

改用标记@Serializable的数据类后,仍报同类错误:

@Serializable
data class Oauth constructor(
    @SerialName("expires_in")
    val expiration: Int,
    @SerialName("token_type")
    val tokenType:String,
    @SerialName("access_token")
    val accessToken: String
)

更新后的错误信息

io.ktor.client.call.NoTransformationFoundException: 
No transformation found: class io.ktor.utils.io.ByteBufferChannel -> class com.company.Oauth

解决方法

核心原因

submitForm默认发送application/x-www-form-urlencoded格式请求,但OAuth2 token端点返回的JSON响应可能未被Ktor正确识别——要么是响应头的Content-Type未标记为application/json,要么是ContentNegotiation配置不完整,导致JSON反序列化逻辑未触发。

具体修复步骤

  1. 确认依赖齐全
    确保项目已引入Ktor JSON序列化相关依赖(以Gradle Kotlin DSL为例):

    implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion")
    implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion")
    
  2. 完善ContentNegotiation配置
    给json()添加必要的序列化规则,比如忽略未知字段(避免响应有额外字段时失败):

    install(ContentNegotiation) {
        json(Json {
            ignoreUnknownKeys = true
            isLenient = true
        })
    }
    
  3. 显式指定反序列化类型
    调用body()时明确指定目标类型,确保Ktor触发JSON转换:

    val oauthResults: Oauth = runBlocking {
        ref<HttpClient>("oauthClient").submitForm(
            url = "${env["oauth.url"]!!}/ms_oauth/oauth2/endpoints/oauthservice/tokens",
            formParameters = Parameters.build {
                append("grant_type", "password")
                append("scope", "bug.rest.public")
                append("username", env["ssoUsername"]!!)
                append("password", env["ssoPassword"]!!)
            }
        ).body<Oauth>()
    }
    
  4. 排查响应状态与内容
    暂时注释expectSuccess = true,打印响应状态码和原始内容,确认请求是否成功、响应是否为有效JSON:

    val response = ref<HttpClient>("oauthClient").submitForm(...)
    println("Response status: ${response.status}")
    println("Response content: ${response.readText()}")
    

验证修复

修改后重新运行代码,确认能正常将响应反序列化为目标类型。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 14:41:34