我遇到了一个奇怪的行为,在类型为“具体化”的函数中使用Gson进行反序列化。仅当类型参数中涉及接口时才会发生这种情况。
采用以下代码:
val toBeSerialized = listOf("1337")
with(Gson()) {
val ser = toJson(toBeSerialized)
val deser = fromJson<List<Serializable>>(ser)
}
第4行使用自定义扩展函数Gson。fromJson(json:String):T。
如果定义为具体化,则失败:
inline fun <reified T> Gson.fromJson(json: String): T = fromJson<T>(json, object : TypeToken<T>() {}.type)
如果它被定义为普通类型参数,它就可以工作:
fun <T> Gson.fromJson(json: String): T = fromJson<T>(json, object : TypeToken<T>() {}.type)
(注意,使T
具体化在这里没有意义,只是想了解它在特殊用例中的影响)
使用具体化时的异常如下所示:
Exception in thread "main" java.lang.RuntimeException: Unable to invoke no-args constructor for ? extends java.io.Serializable. Registering an InstanceCreator with Gson for this type may fix this problem.
at com.google.gson.internal.ConstructorConstructor$14.construct(ConstructorConstructor.java:226)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:210)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:41)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:82)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61)
at com.google.gson.Gson.fromJson(Gson.java:888)
at com.google.gson.Gson.fromJson(Gson.java:853)
at com.google.gson.Gson.fromJson(Gson.java:802)
at SoTestsKt.main(SoTests.kt:25)
Caused by: java.lang.UnsupportedOperationException: Interface can't be instantiated! Interface name: java.io.Serializable
at com.google.gson.internal.UnsafeAllocator.assertInstantiable(UnsafeAllocator.java:117)
at com.google.gson.internal.UnsafeAllocator$1.newInstance(UnsafeAllocator.java:49)
at com.google.gson.internal.ConstructorConstructor$14.construct(ConstructorConstructor.java:223)
... 8 more
正如@jornvernee所提到的,序列化/反序列化json需要具体化。如果未添加具体化的,它将被视为列表
要序列化/反序列化接口,需要注册一个自定义适配器来添加所实现类的类型信息。这里是一个适配器类,我从该站点引用它并对其进行一些更改。
class InterfaceAdapter<T : Serializable> : JsonSerializer<T>, JsonDeserializer<T> {
companion object {
private val CLASSNAME = "CLASSNAME"
private val DATA = "DATA"
}
@Throws(JsonParseException::class)
override fun deserialize(jsonElement: JsonElement, type: Type, jsonDeserializationContext: JsonDeserializationContext): T {
val jsonObject = jsonElement.asJsonObject
val prim = jsonObject.get(CLASSNAME) as JsonPrimitive
val className = prim.asString
val klass = getObjectClass(className)
return jsonDeserializationContext.deserialize(jsonObject.get(DATA), klass)
}
override fun serialize(jsonElement: T, type: Type, jsonSerializationContext: JsonSerializationContext): JsonElement {
val jsonObject = JsonObject()
jsonObject.addProperty(CLASSNAME, jsonElement.javaClass.name)
jsonObject.add(DATA, jsonSerializationContext.serialize(jsonElement))
return jsonObject
}
private fun getObjectClass(className: String): Class<*> {
try {
return Class.forName(className)
} catch (e: ClassNotFoundException) {
throw JsonParseException(e.message)
}
}
}
将适配器注册到gson对象并提供类型信息。
inline fun <reified T> Any.toJson(): String {
val builder = GsonBuilder()
builder.registerTypeAdapter(Serializable::class.java, InterfaceAdapter<Serializable>())
val gson = builder.create()
return gson.toJson(this, object : TypeToken<T>() {}.type)
}
inline fun <reified T> fromJson(json: String): T {
val builder = GsonBuilder()
builder.registerTypeAdapter(Serializable::class.java, InterfaceAdapter<Serializable>())
val gson = builder.create()
return gson.fromJson<T>(json, object : TypeToken<T>() {}.type)
}
示例代码:
data class User(val name: String) : Serializable
val data = listOf(User("Sam"))
val ser = data.toJson<List<Serializable>>()
val deser = fromJson<List<Serializable>>(ser)
println(ser)
println(deser.get(0)::class)
println(deser.get(0))
/* Output
[{"CLASSNAME":"User","DATA":{"name":"Sam"}}]
class User
User(name=Sam)
*/
使用具体化T的版本失败,因为它试图将“1337”反序列化为可序列化的,这是一个接口,因此无法实例化,默认情况下,没有类型适配器可以反序列化为可序列化的
在非具体化版本中,没有实际的类型信息传递给扩展函数。您可以通过打印从令牌获取的类型来验证这一点:
fun <T> Gson.fromJson(json: String): T {
val tt = object : TypeToken<T>() {}.type;
println(tt);
return fromJson(json, tt);
}
在无具体化版本中,它只打印T
(即没有可用的实际类型信息),但在具体化
版本中,它将打印实际类型(任何静态编程语言声明站点差异修饰符,因此列表
非具体化版本之所以有效,是因为巧合。因为Gson反序列化的默认类型是ArrayList
如果您稍微修改示例,例如通过指定不同类型的列表来执行不同的强制转换,则会遇到问题:
val deser = fromJson<LinkedList<Serializable>>(ser)
抛出java。lang.ClassCastException:java。util。ArrayList无法转换为java。util。LinkedList
您需要具体化T
才能传递类型信息,但这也意味着失败将更早发生,并且不会因为类型擦除而被忽视,就像在非具体化
版本中一样。
我有一个kotlin库项目,并使用进行测试。在我的测试中,我尝试使用以下函数: 是正确的行为吗?
是否有一种方法可以通过反射获得具体化泛型的实际类型参数?
我有一个抽象超类和两个非抽象子类和。如何在超类方法中定义类型,如下所示 我允许在子类方法中编写具体类型(例如,或) 在上面的示例中,子类方法不会覆盖超类方法。
我不熟悉泛型。我有一个抽象类(1)和一个抽象方法。我有另一个抽象类(2)和一些抽象方法,我希望在一些DTO(3,4)中共享这些抽象方法。我想要一个(1)的具体扩展来处理任何扩展(2)的东西。 1. 扩展StagingError的两个类:3.
我想使用Google Gson库(de)序列化一个具有参数化成员字段的参数化类型。 这将引发
我正在尝试从相应的字符串值填充Kotlin数据类。我使用GSON查看了来自Json的:Kotlin数据类,但我试图做的并不是跟踪完全相同的: 调用此函数并尝试填充以下类: 但没有欢乐。stringValue是gson.toJson(value)生成的东西,其中value是一个JSONObject。 有人知道我的断线是什么吗?