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

如何在Gson中启用严格类型校验?

问题:Gson自动转换类型不匹配的JSON字段,如何禁用这种宽松行为?

我在用Gson解析JSON时发现一个意外行为:当POJO的String字段对应JSON里的number值,或者Int字段对应JSON里的string值时,Gson会自动完成类型转换,不会抛出异常。以下测试用例可以复现这个问题:

data class Parsed(
    val testString: String,
    val testNumber: Int,
)

@Test
fun `test gson type parsing`() {
    val gson = Gson()

    val json = "{ \"testString\" : 1, \"testNumber\" : \"1\"}"

    val parsed = gson.fromJson(json, Parsed::class.java)

    assertThat(parsed.testString).isEqualTo("1") // 测试通过
    assertThat(parsed.testNumber).isEqualTo(1) // 测试通过
    // 原本预期类型不匹配时抛出异常,但实际没有
}

我只找到GsonBuilder.setLenient()方法,但它和这个问题无关,请问有没有办法修改Gson的这种行为?


解决方案

Gson默认的宽松类型转换是为了兼容不规范的JSON数据,但如果需要严格的类型校验,可以通过自定义TypeAdapter来实现,强制检查JSON原始类型与POJO字段类型是否匹配:

1. 为单个类型编写严格的TypeAdapter

针对需要严格校验的类型(比如String、Int),编写对应的TypeAdapter,解析时判断JSON token类型,不匹配则抛出异常:

String类型的严格适配器

class StrictStringAdapter : TypeAdapter<String>() {
    override fun write(out: JsonWriter, value: String?) {
        out.value(value)
    }

    override fun read(`in`: JsonReader): String {
        if (`in`.peek() != JsonToken.STRING) {
            throw JsonSyntaxException("预期String类型,但实际是${`in`.peek()},路径:${`in`.path}")
        }
        return `in`.nextString()
    }
}

Int类型的严格适配器

class StrictIntAdapter : TypeAdapter<Int>() {
    override fun write(out: JsonWriter, value: Int?) {
        out.value(value)
    }

    override fun read(`in`: JsonReader): Int {
        if (`in`.peek() != JsonToken.NUMBER) {
            throw JsonSyntaxException("预期Number类型,但实际是${`in`.peek()},路径:${`in`.path}")
        }
        return `in`.nextInt()
    }
}

2. 注册适配器到GsonBuilder

将自定义的TypeAdapter注册到Gson实例中,替换默认的类型转换逻辑:

val gson = GsonBuilder()
    .registerTypeAdapter(String::class.java, StrictStringAdapter())
    .registerTypeAdapter(Int::class.java, StrictIntAdapter())
    .create()

此时再运行原测试用例,Gson会抛出JsonSyntaxException,符合类型不匹配时抛出异常的预期。

3. 批量处理多个类型(可选)

如果需要对多个基本类型都做严格校验,可以编写TypeAdapterFactory统一管理:

class StrictTypeAdapterFactory : TypeAdapterFactory {
    override fun <T> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
        val rawType = type.rawType
        return when {
            rawType == String::class.java -> StrictStringAdapter() as TypeAdapter<T>
            rawType == Int::class.java -> StrictIntAdapter() as TypeAdapter<T>
            // 可扩展添加Long、Double等其他需要严格校验的类型
            else -> null
        }
    }
}

注册方式:

val gson = GsonBuilder()
    .registerTypeAdapterFactory(StrictTypeAdapterFactory())
    .create()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 21:07:03