当Gson TypeAdapter访问无效字段时,是否支持跳过值解析?

qyyhg6bp  于 2022-11-06  发布在  其他
关注(0)|答案(1)|浏览(251)

背景

我有一个数据类:

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()
    }
}

问题

我的问题是对代码的评论:
1.当gson访问一个其值为空字段时,如何跳过该值的解析并使用Kotlin数据类的默认值?
1.当gson访问一个值为long值字段时,解析到Int时会发生溢出异常(NumberFormatException),如何跳过该值的解析,而使用Kotlin数据类的默认值?
感谢您的回答!

envsm3lx

envsm3lx1#

最后,我自定义一个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时,如果值不为空或不是原语,则将值设置到该字段中。
但该值为null,并且是基元值,因此不会设置该字段,而是使用默认值。

相关问题