gson null_将gson与kotlins非null类型一起使用

gson null

结合GSON和Kotlin的问题 (The problem combining GSON and Kotlin)

With more and more people using Kotlin, it was inevitable that programmers would use it alongside the most popular Java JSON library, Google’s GSON. Even though these tools are compatible, there are elements of Kotlin that GSON doesn’t quite understand.

随着越来越多的人使用Kotlin,程序员不可避免地将其与最受欢迎的Java JSON库( Google的GSON)一起使用 。 即使这些工具兼容,但GSON并不十分了解Kotlin的某些元素。

GSON doesn’t understand Kotlin’s non-null types

GSON不了解Kotlin的非null类型

This means that if you try to deserialize a null value into a non-null type, GSON will do so without errors. This can easily cause unexpected exceptions.

这意味着,如果您尝试将null值反序列化为非null类型,则GSON将这样做而不会出错。 这很容易导致意外的异常。

An example of the problem:

问题的一个示例:

data class Person(val name: String, val age: Int)
fun main() {
val gson = GsonBuilder().create()
val personString = """
{
"name": null,
"age": 25
}
""".trimIndent()
val person = gson.fromJson(personString, Person::class.java)println(person.name.trim()) // TypeCastException
}

Kotlin’s nullable types promise us that if a value can be null, it will either be marked as nullable, or at least marked as a platform type, meaning it comes from Java.

Kotlin的可为空的类型向我们保证,如果值可以为null,则它将被标记为可为空,或者至少被标记为平台类型 ,这意味着它来自Java。

However, this is very clearly a non-null member that is null. How can this happen? Well, GSON uses reflection by default, and can therefore skirt the normal language rules when it comes to classes.

但是,很明显,这是一个非null成员,它为null。 怎么会这样 好吧,GSON默认情况下使用反射,因此在涉及类时可以略过常规语言规则。

我们该如何解决? (How do we fix this?)

The simple answer is more reflection! The first thing we need is Kotlin’s full Reflection Library, which you can get here.

简单的答案就是更多的反思! 我们需要的第一件事是Kotlin完整的反射库,您可以在这里找到

Once you have that library (and GSON), we can create a special TypeAdapterFactory. By creating this class and using GSON’s DelegateAdapter, we can inject some custom logic that occurs before each value is deserialized.

一旦有了该库(和GSON),我们就可以创建一个特殊的TypeAdapterFactory 。 通过创建此类并使用GSON的DelegateAdapter,我们可以注入一些在反序列化每个值之前发生的自定义逻辑。

NullableTypeAdapterFactor.kt (NullableTypeAdapterFactor.kt)

import com.google.gson.*
import com.google.gson.reflect.TypeToken
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonWriter
import kotlin.jvm.internal.Reflection
import kotlin.reflect.KClass
import kotlin.reflect.full.memberPropertiesclass NullableTypAdapterFactory : TypeAdapterFactory {
override fun <T : Any> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
val delegate = gson.getDelegateAdapter(this, type)
// If the class isn't kotlin, don't use the custom type adapter
if (type.rawType.declaredAnnotations.none { it.annotationClass.qualifiedName == "kotlin.Metadata" }) {
return null
}
return object : TypeAdapter<T>() {
override fun write(out: JsonWriter, value: T?) = delegate.write(out, value)
override fun read(input: JsonReader): T? {
val value: T? = delegate.read(input)
if (value != null) {
val kotlinClass: KClass<Any> = Reflection.createKotlinClass(type.rawType)
// Ensure none of its non-nullable fields were deserialized to null
kotlinClass.memberProperties.forEach {if (!it.returnType.isMarkedNullable && it.get(value) == null) {
throw JsonParseException("Value of non-nullable member [${it.name}] cannot be null")
}}}
return value
}
}
}
}

We can register an instance of this class to a GSON object, which will allow that GSON object to properly deserialize Kotlin’s non-nullable types. The end result is that we get an exception when the parser finds a null value for a non-null field.

我们可以将此类的实例注册到GSON对象,这将允许该GSON对象正确反序列化Kotlin的不可为null的类型。 最终结果是, 当解析器为非null字段找到null值时我们将获得异常

This makes the process much easier to anticipate and handle. Now we can do:

这使得该过程更容易预期和处理。 现在我们可以做:

data class Person(val name: String, val age: Int)
fun main() {
val gson = GsonBuilder()
.registerTypeAdapterFactory(NullableTypAdapterFactory())
.create()
val personString = """
{
"name": null,
"age": 25
}
""".trimIndent()
val person = gson.fromJson(personString, Person::class.java) // JsonParseExceptionprintln(person.name.trim())
}

Now we can fully utilize Kotlin’s nullability in our data classes and handle the parsing issues in one step.

现在,我们可以在数据类中充分利用Kotlin的可为空性,并一步一步地处理解析问题。

但这如何工作? (But how does this work?)

Essentially, whenever GSON goes to deserialize something, it will ask the type adapter factory to provide a type adapter for the type it’s trying to deserialize.

本质上,每当GSON进行反序列化时,它都会要求类型适配器工厂为其尝试进行反序列化的类型提供类型适配器。

The NullableTypeAdapterFactory will first check if the type is a Kotlin type. If not, it will let GSON use the default adapter. Otherwise, we return a custom one.

NullableTypeAdapterFactory将首先检查类型是否为Kotlin类型。 如果没有,它将让GSON使用默认适配器。 否则,我们将返回一个自定义的。

The custom one first gets the “delegateAdapter”, which is essentially the adapter that GSON would have used if you didn’t give it one. With this adapter, we deserialize the object.

自定义的第一个获得的是“ delegateAdapter”,如果您不给它一个,那么它实际上就是GSON 会使用的适配器。 使用此适配器,我们可以反序列化对象。

From there, we use Kotlin’s reflection library to peer into the object’s class and find the non-nullable fields. If one of the fields is non-null and the object’s value for that field is null, then we throw an exception. If none of these are found, we return the deserialized object.

从那里,我们使用Kotlin的反射库来窥视对象的类并找到不可为空的字段。 如果其中一个字段为非null,并且该字段的对象值为null,则抛出异常。 如果找不到这些,我们将返回反序列化的对象。

使用此适配器工厂是否有不利之处? (Are there any downsides to using this adapter factory?)

Yes. Firstly, this requires an external dependency (Kotlin’s full reflection library), which adds a bit more size to your final deliverable.

是。 首先,这需要外部依赖项(Kotlin的完整反射库),这将为最终交付物增加更多的空间。

It also adds overhead, as we are essentially inspecting each kotlin object after it gets deserialized. GSON is already known for trading convenience for runtime speed, and this technique does the same. We’re slowing down the deserialization process in order to obtain null-safety.

这也增加了开销,因为在反序列化之后,我们实际上是在检查每个kotlin对象。 GSON以运行时速度的交易便利性而闻名,这种技术也可以做到这一点。 为了获得空安全性,我们正在减慢反序列化过程。

结论 (Conclusion)

If you need or want to use GSON and Kotlin together, and don’t need a lot of optimization in your parsing, this technique is immensely useful for enforcing code safety.

如果您需要或想要一起使用GSON和Kotlin,并且在解析时不需要太多优化,则此技术对于强制执行代码安全性非常有用。

However, there are other libraries that support Kotlin nullable types out-of-the-box, such as Jackson or Moshi. Jackson is one of the most widely-used JSON libraries for Java, and Moshi is a particularly modern framework that specifically supports Kotlin.

但是,还有其他支持开箱即用的Kotlin可空类型的库,例如JacksonMoshi 。 Jackson是Java中使用最广泛的JSON库之一,而Moshi是专门支持Kotlin的特别现代的框架。

翻译自: https://medium.com/swlh/using-gson-with-kotlins-non-null-types-468b1c66bd8b

gson null

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值