使用 gson 序列化并返回不适用于泛型类型
serializing with gson and back does not work with generic types
我正在编写一个 kotlin websocket,并希望发送使用 gson 转换为 json 的 dto。所以我写了一种包装器 dto,其中包含真正的 dto 和一些关于 dto 的附加信息,比如它的类型。这是我的包装器 dto
class WrapperDto <T : AbstractDto> {
var type = ""
var action = ""
var dto : T = AbstractDto() as T
}
这是它可以包含的 dto 之一:
class Person : AbstractDto() {
var firstName = ""
var familyName = ""
}
这里出于测试原因,我尝试将其转换为 json 然后再转换回来:
val wrapperDto2 = WrapperDto<Person>()
wrapperDto2.type = Person::class.simpleName!!;
wrapperDto2.action = "add"
val person = Person()
person.firstName = "Richard"
person.familyName = "Lederer"
wrapperDto2.dto = person;
val gson1 = Gson()
val toJson = gson1.toJson(wrapperDto2)
println("to json: " + toJson)
val fromJson = gson1.fromJson(toJson, wrapperDto2::class.java)
println("from json: " + fromJson)
最后一个 println 从未被调用,我收到以下错误消息:
java.lang.IllegalArgumentException: Can not set at.richardlederer.contactmanager.dto.AbstractDto field at.richardlederer.contactmanager.dto.WrapperDto.dto to com.google.gson.internal.LinkedTreeMap
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:81)
我该如何解决这个问题?
这是由于type erasure of generics. You need to use TokenType
在运行时检索类型信息。
val fromJson = gson1.fromJson<WrapperDto<Person>>(toJson, object: TypeToken<WrapperDto<Person>>() {}.type)
您也可以像这样创建一个扩展函数:
inline fun <reified T> fromJson(json: String): T = Gson().fromJson<T>(json, object: TypeToken<T>() {}.type)
因此,您可以这样调用 fromJson
:
val fromJson = fromJson<WrapperDto<Person>>(toJson)
//Or
val fromJson: WrapperDto<Person> = fromJson(toJson) //Type inferred
我正在编写一个 kotlin websocket,并希望发送使用 gson 转换为 json 的 dto。所以我写了一种包装器 dto,其中包含真正的 dto 和一些关于 dto 的附加信息,比如它的类型。这是我的包装器 dto
class WrapperDto <T : AbstractDto> {
var type = ""
var action = ""
var dto : T = AbstractDto() as T
}
这是它可以包含的 dto 之一:
class Person : AbstractDto() {
var firstName = ""
var familyName = ""
}
这里出于测试原因,我尝试将其转换为 json 然后再转换回来:
val wrapperDto2 = WrapperDto<Person>()
wrapperDto2.type = Person::class.simpleName!!;
wrapperDto2.action = "add"
val person = Person()
person.firstName = "Richard"
person.familyName = "Lederer"
wrapperDto2.dto = person;
val gson1 = Gson()
val toJson = gson1.toJson(wrapperDto2)
println("to json: " + toJson)
val fromJson = gson1.fromJson(toJson, wrapperDto2::class.java)
println("from json: " + fromJson)
最后一个 println 从未被调用,我收到以下错误消息:
java.lang.IllegalArgumentException: Can not set at.richardlederer.contactmanager.dto.AbstractDto field at.richardlederer.contactmanager.dto.WrapperDto.dto to com.google.gson.internal.LinkedTreeMap
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:81)
我该如何解决这个问题?
这是由于type erasure of generics. You need to use TokenType
在运行时检索类型信息。
val fromJson = gson1.fromJson<WrapperDto<Person>>(toJson, object: TypeToken<WrapperDto<Person>>() {}.type)
您也可以像这样创建一个扩展函数:
inline fun <reified T> fromJson(json: String): T = Gson().fromJson<T>(json, object: TypeToken<T>() {}.type)
因此,您可以这样调用 fromJson
:
val fromJson = fromJson<WrapperDto<Person>>(toJson)
//Or
val fromJson: WrapperDto<Person> = fromJson(toJson) //Type inferred