如何在Kotlin中借助Gson处理伪布尔型异常字符串?
处理Gson中字符串转布尔值的最优方案
碰到这种没法修改的API返回格式确实头疼,不过用Gson在Kotlin里有几种优雅的处理方式,既能把"yes"/"no"、"on"/"off"(还能兼容大小写)转成布尔值用,也能在序列化时转回去对应字符串,我给你详细说下:
方案一:自定义TypeAdapter(推荐,支持双向序列化)
这是最灵活的方式,写一个通用的适配器来处理这类字符串和布尔值的转换,不管大小写都能兼容,还能同时支持反序列化(JSON转数据类)和序列化(数据类转JSON)。
1. 编写布尔字符串适配器
import com.google.gson.TypeAdapter import com.google.gson.stream.JsonReader import com.google.gson.stream.JsonWriter import com.google.gson.JsonSyntaxException class BooleanStringAdapter : TypeAdapter<Boolean>() { // 序列化:把布尔值转成API需要的字符串(这里根据需求调整,比如true转"On"还是"Yes") override fun write(out: JsonWriter, value: Boolean?) { val stringValue = when (value) { true -> "On" // 或者"Yes",看API要求的输出格式 false -> "Off" null -> throw JsonSyntaxException("Boolean value cannot be null") } out.value(stringValue) } // 反序列化:把JSON里的字符串转成布尔值,兼容大小写和前后空格 override fun read(`in`: JsonReader): Boolean { val stringValue = `in`.nextString().trim().lowercase() return when (stringValue) { "yes", "on" -> true "no", "off" -> false else -> throw JsonSyntaxException("Invalid boolean string: $stringValue") } } }
2. 注册适配器到Gson
要同时注册包装类和原始类型,避免Gson处理时出现遗漏:
import com.google.gson.GsonBuilder val gson = GsonBuilder() .registerTypeAdapter(Boolean::class.java, BooleanStringAdapter()) .registerTypeAdapter(Boolean::class.javaPrimitiveType, BooleanStringAdapter()) .create()
3. 修改数据类为布尔字段
现在数据类可以直接用布尔类型,不用再处理字符串:
data class APIdata( val value: Boolean, val anotherValue: Boolean )
测试效果
// 反序列化示例JSON val json = """{"value" : "On", "anotherValue" : "Yes"}""" val apiData = gson.fromJson(json, APIdata::class.java) println(apiData.value) // 输出 true println(apiData.anotherValue) // 输出 true // 序列化回JSON val serializedJson = gson.toJson(apiData) println(serializedJson) // 输出 {"value":"On","anotherValue":"On"}(如果write方法里true转"On"的话)
方案二:针对特定字段使用@JsonAdapter
如果只有个别字段需要这种转换,其他字段是正常的布尔值或类型,可以不用全局注册适配器,直接在字段上标注@JsonAdapter注解:
import com.google.gson.annotations.JsonAdapter data class APIdata( @JsonAdapter(BooleanStringAdapter::class) val value: Boolean, @JsonAdapter(BooleanStringAdapter::class) val anotherValue: Boolean )
这种方式更精准,不会影响其他字段的序列化逻辑。
方案三:数据类封装(仅反序列化场景)
如果只需要解析JSON,不需要把数据类再转成JSON回去,可以在数据类里把字符串字段设为私有,对外暴露计算属性来得到布尔值:
import com.google.gson.annotations.SerializedName data class APIdata( @SerializedName("value") private val valueString: String, @SerializedName("anotherValue") private val anotherValueString: String ) { // 对外暴露布尔属性,自动转换字符串 val value: Boolean get() = valueString.trim().lowercase() in setOf("yes", "on") val anotherValue: Boolean get() = anotherValueString.trim().lowercase() in setOf("yes", "on") }
注意:这种方式下,如果用Gson把APIdata转成JSON,会输出valueString和anotherValueString这两个字段,而不是原来的value和anotherValue,所以只适合纯解析的场景。
总结
如果需要双向序列化(解析+生成JSON),方案一或方案二是最优选择,灵活且符合Gson的设计规范;如果只是单纯解析JSON,方案三也能快速解决问题。
内容的提问来源于stack exchange,提问作者soundsofpolaris
相关产品推荐
相关产品推荐

