android - Gson TypeAdapter 在访问无效字段时是否支持跳过值解析?
问题描述
背景
我有一个数据类:
data class Foo(
@SerializedName("foo")
val foo: Int = 1000
)
我想使用这个 IntSafeTypeAdapter 反序列化为 Foo 对象。但是 json 字符串会foo
意外返回一个无效的。所以我定制了一个 Gson TypeAdapter 来解决它。
还有一个 Gson 类型适配器:
class IntSafeTypeAdapter : TypeAdapter<Int>() {
override fun write(reader: JsonWriter?, intValue: Int?) {
reader?.value(intValue ?: return)
}
override fun read(reader: JsonReader?): Int {
val numStr = reader?.nextString()
if (numStr == null) {
// 1. How to skip this field and using kotlin data class default value
// when there is no value of this field?
return 0
}
if (numStr.toLong().toInt() != numStr.toInt()) {
// 2. How to skip this field and using kotlin data class
// when there is a long value?
return numStr.toInt()
}
// common condition
return numStr.toInt()
}
}
问题
我的问题是对代码的评论:
- 当 gson 访问其值为 null 的字段时,如何跳过该值的解析并改用 kotlin 数据类默认值?
- 当 gson 访问一个其值为 long 值的字段时,解析为 Int 时会发生溢出异常(NumberFormatException),如何跳过该值的解析并改用 kotlin 数据类默认值?
感谢您的回答!
解决方案
最后,我自定义了一个 TypeAdapter 来做到这一点:
class IntSafeTypeAdapter: TypeAdapter<Int?>() {
override fun write(reader: JsonWriter?, intValue: Int?) {
reader?.value(intValue ?: return)
}
override fun read(reader: JsonReader?): Int? {
val numberStr = reader?.nextString() ?: return null
return try {
numberStr.toInt()
} catch (e: NumberFormatException) {
// if return null, primitive field will not be set value
null
}
}
}
并在构建 Gson 实例时注册TypeAdapter:
val gson by lazy {
GsonBuilder().registerTypeAdapter(Int::class.java, IntSafeTypeAdapter())
.create()
}
它是如何工作的?我们可以阅读 Gson 源代码ReflectiveTypeAdapterFactory
来找到答案:
// ReflectiveTypeAdapterFactory
public final class ReflectiveTypeAdapterFactory implements TypeAdapterFactory {
...
private ReflectiveTypeAdapterFactory.BoundField createBoundField(...) {
...
return new ReflectiveTypeAdapterFactory.BoundField(...) {
...
@Override void read(JsonReader reader, Object value)
throws IOException, IllegalAccessException {
Object fieldValue = typeAdapter.read(reader);
if (fieldValue != null || !isPrimitive) { // <<<<<< here
field.set(value, fieldValue);
}
}
...
}
}
...
}
执行时ReflectiveTypeAdapterFactory.BoundField.read
,如果 value 不为 null 或不是原始的,则 value 将设置到该字段中。
但是该值为 null 并且它是原始的,因此不会设置该字段并使用默认值。
推荐阅读
- android - 如何使垂直滚动列表与视图寻呼机同步
- android - Android 应用上的 Admob 个性化广告用户同意
- kubernetes - 如何在 Kubernetes 中使用来自 Airflow 的 DockerOperator
- c# - UWP - 修改文件时 RandomAccessStream 退出
- c - 在 C 中,我如何访问/迭代动态添加到 fd_set 的文件描述符?
- python - 尝试创建 Django 迁移时,ForeignKey 缺少必需的位置参数 on_delete
- android - 配置“编译”已过时,已替换为“实施”和“API”
- python - 从数据框中删除第一个字母为小写的行
- javascript - 主干模型中的相对 URL,到与浏览器 url 中不同形式的端口
- javascript - 将 jsonarray 拆分为块数组到另一个数组中