com.google.gson.internal.LinkedTreeMap 无法转换为我的自定义 class
com.google.gson.internal.LinkedTreeMap cannot be cast to my custom class
我得到:
com.google.gson.internal.LinkedTreeMap cannot be cast to Message class
我想将任何类型的对象转换为我的自定义 class。我正在尝试 gson 将对象转换为 JSON,然后将 JSON 字符串转换为我的 Message
class。
我使用 Gson 创建了一个具有通用类型转换的函数。
//Custom Class
data class Message(
@SerializedName("content")
val content: String? = null
)
//My abstract class
abstract class EchoListener<T> {
companion object {
private val TAG = EchoListener::class.java.simpleName
}
abstract fun onDataReceived(data: T?)
fun submitData(it: Any) {
Log.e(TAG, "Echio data ${it}")
val gson = Gson()
val json = gson.toJson(it)
val data: EchoData<T> = gson.fromJson(json, genericType<EchoData<T>>())
Log.e(TAG, "Converted data ${data.data}")
onDataReceived(data.data)
}
}
inline fun <reified T> genericType() = object : TypeToken<T>() {}.type
class SomeClass {
fun <T> listen(event: String, callback: EchoListener<T>) {
val listener = Emitter.Listener {
Log.e(TAG, "Data ${it[1]}")
if (it.size > 1)
callback.submitData(it[1])
}
this.socket.on(event, listener)
this.bind(event, listener)
}
}
//Main Activity
someClassObj?.listen("chat", object : EchoListener<Message>() {
override fun onDataReceived(data: Message?) {
Log.e(TAG, "Message ${data}")
}
})
已编辑
这是我正在创建的库的link:
Github repo
这是示例 android 应用程序
Android Github Repo
这可以使用 kotlinx.serialization in a fairly simple way. First, see an exmple 来完成以了解其工作原理,然后将库依赖项添加到应用程序 build.gradle:
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.13.0"
请注意,要能够在您的 Kotlin 代码中使用 Kotlin 序列化库,请确保您的 Kotlin 编译器版本为 1.3.30
或更高版本。
现在您需要使用 @Serializable
注释对您想要 serialize/deserialize 的所有 class 进行注释,并确保您从 kotlinx.serialization.Serializable
导入。
注释完 classes 后,编译器会在 Java 字节代码中为每个 class 自动生成一个称为 serializer()
的静态函数,我们将调用此函数以序列化和反序列化 class.
的对象
现在要实现通用 serialize/deserialize 功能,请将此文件添加到您的项目中:
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerializationStrategy
import kotlinx.serialization.json.Json
object SerializationManager {
fun <T> deserializeObject(
json: String,
deserializationStrategy: DeserializationStrategy<T>
): T = Json.parse(deserializationStrategy, json)
fun <T> getList(json: String, dataSerializer: KSerializer<List<T>>): List<T> =
Json.parse(dataSerializer, json)
fun <T> serializeObject(data: T, serializationStrategy: SerializationStrategy<T>): String =
Json.stringify(serializationStrategy, data)
fun <T> serializeList(
data: List<T>,
dataSerializer: KSerializer<List<T>>
): String = Json.stringify(dataSerializer, data)
}
如何使用 SerializationManager 的示例
我有一个 Reciter
class 想要连载:
import kotlinx.serialization.Serializable
@Serializable
data class Reciter(
val id: String,
val name: String,
val servers: String
)
然后在您的 Activity
或其他地方:
val reciter = Reciter("A123", "ABCD", "https://whosebug.com")
val json1 = SerializationManager.serializeObject(reciter, Reciter.serializer())
// If we want to serialize a list of reciters, then we pass Reciter.serializer().list
val recitersList = listOf(
Reciter("A123", "ABCD", "https://whosebug.com"),
Reciter("B456", "F.abc", "https://whosebug.com"),
Reciter("M568", "NDK", "https://whosebug.com")
)
val json2 = SerializationManager.serializeList(recitersList,Reciter.serializer().list)
您尝试以非常复杂的方式使用它。使用 Gson
.
会容易得多
这里有四种扩展方法,几乎涵盖了您需要的所有情况。如果没有 - 我希望您能根据这些找出其余部分。
inline fun <reified T> T.toJson(): String = Gson().toJson(this)
inline fun <reified T> String.toObject(): T = Gson().fromJson(this, T::class.java)
inline fun <reified T, K, V> Map<K, V>.toObject(): T = Gson().fromJson(this.toJson(), T::class.java)
// and more classic but less used
fun <T> String.toObject(type: Type): T = Gson().fromJson(this, type)
现在可以像
一样使用了
data class SomeClass(val today: Int, val yesterday: Int)
val someClass = SomeClass(3,4)
val json = someClass.toJson() // { "today" : 3,"yesterday" : 4 }
val someClassDesetialized = json.toObject<SomeClass>() // SomeClass(3,4)
val map: Map<String, Int> = mapOf("today" to 2,"yesterday" to 1)
val mapJson= map.toJson() // { "today" : 2,"yesterday" : 1 }
val someClassFromMap = map.toObject<SomeClass, String, Int>() // SomeClass(2,1)
val someClassFromMapJson: SomeClass = mapJson.toObject<SomeClass>().copy(5) // SomeClass(5,1)
...
val data: EchoData<T> = json.toObject()
val data1 = json.toObject<EchoData<T>>()
类似的东西。请注意,Gson lib 使用 Java serialization so it maybe slower and less secure than Kotlin specific kotlinx.serialization 但它不像 kotlinx.serialization 那样处于 prealpha 版本,因此它不易出错且更成熟。
编辑1
这里是如何以非常符合行业标准的方式隐藏转换。
inline fun <reified T> Map<String, Any>.convert(): T = toObject()
然后像
一样使用它
map.convert<SomeClass>()
它比将 Type 作为方法参数传递更好。
您必须调整此方法才能在 Java 代码中使用。 Here 解释了如何操作。
编辑2
这是您的应用已修复的架构问题
你的例子中的一些类应该是
class SomeClass {
inline fun <reified T> listen(event: String, callback: (T) -> Unit) {
Emitter.Listener {
Log.e(TAG, "Data ${it[1]}")
if (it.size > 1)
// I don't know what it[1] is so I assume it is map<String, Any> since it was in an original issue.
callback((it[1] as Map<String, Any>).toObject<T, String, Any>())
}.apply{
this@SomeClass.socket.on(event, this)
this@SomeClass.bind(event, this)
}
}
}
当它的使用量现在可以减少到
SomeClass().listen<Message>("someEvent", { message ->
// do some stuff with message
})
这不是从 Map 到 Pojo 的原始转换问题的修复。这是有缺陷的方法的架构修复。
希望对您有所帮助。
我得到:
com.google.gson.internal.LinkedTreeMap cannot be cast to Message class
我想将任何类型的对象转换为我的自定义 class。我正在尝试 gson 将对象转换为 JSON,然后将 JSON 字符串转换为我的 Message
class。
我使用 Gson 创建了一个具有通用类型转换的函数。
//Custom Class
data class Message(
@SerializedName("content")
val content: String? = null
)
//My abstract class
abstract class EchoListener<T> {
companion object {
private val TAG = EchoListener::class.java.simpleName
}
abstract fun onDataReceived(data: T?)
fun submitData(it: Any) {
Log.e(TAG, "Echio data ${it}")
val gson = Gson()
val json = gson.toJson(it)
val data: EchoData<T> = gson.fromJson(json, genericType<EchoData<T>>())
Log.e(TAG, "Converted data ${data.data}")
onDataReceived(data.data)
}
}
inline fun <reified T> genericType() = object : TypeToken<T>() {}.type
class SomeClass {
fun <T> listen(event: String, callback: EchoListener<T>) {
val listener = Emitter.Listener {
Log.e(TAG, "Data ${it[1]}")
if (it.size > 1)
callback.submitData(it[1])
}
this.socket.on(event, listener)
this.bind(event, listener)
}
}
//Main Activity
someClassObj?.listen("chat", object : EchoListener<Message>() {
override fun onDataReceived(data: Message?) {
Log.e(TAG, "Message ${data}")
}
})
已编辑
这是我正在创建的库的link: Github repo
这是示例 android 应用程序 Android Github Repo
这可以使用 kotlinx.serialization in a fairly simple way. First, see an exmple 来完成以了解其工作原理,然后将库依赖项添加到应用程序 build.gradle:
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.13.0"
请注意,要能够在您的 Kotlin 代码中使用 Kotlin 序列化库,请确保您的 Kotlin 编译器版本为 1.3.30
或更高版本。
现在您需要使用 @Serializable
注释对您想要 serialize/deserialize 的所有 class 进行注释,并确保您从 kotlinx.serialization.Serializable
导入。
注释完 classes 后,编译器会在 Java 字节代码中为每个 class 自动生成一个称为 serializer()
的静态函数,我们将调用此函数以序列化和反序列化 class.
现在要实现通用 serialize/deserialize 功能,请将此文件添加到您的项目中:
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerializationStrategy
import kotlinx.serialization.json.Json
object SerializationManager {
fun <T> deserializeObject(
json: String,
deserializationStrategy: DeserializationStrategy<T>
): T = Json.parse(deserializationStrategy, json)
fun <T> getList(json: String, dataSerializer: KSerializer<List<T>>): List<T> =
Json.parse(dataSerializer, json)
fun <T> serializeObject(data: T, serializationStrategy: SerializationStrategy<T>): String =
Json.stringify(serializationStrategy, data)
fun <T> serializeList(
data: List<T>,
dataSerializer: KSerializer<List<T>>
): String = Json.stringify(dataSerializer, data)
}
如何使用 SerializationManager 的示例
我有一个 Reciter
class 想要连载:
import kotlinx.serialization.Serializable
@Serializable
data class Reciter(
val id: String,
val name: String,
val servers: String
)
然后在您的 Activity
或其他地方:
val reciter = Reciter("A123", "ABCD", "https://whosebug.com")
val json1 = SerializationManager.serializeObject(reciter, Reciter.serializer())
// If we want to serialize a list of reciters, then we pass Reciter.serializer().list
val recitersList = listOf(
Reciter("A123", "ABCD", "https://whosebug.com"),
Reciter("B456", "F.abc", "https://whosebug.com"),
Reciter("M568", "NDK", "https://whosebug.com")
)
val json2 = SerializationManager.serializeList(recitersList,Reciter.serializer().list)
您尝试以非常复杂的方式使用它。使用 Gson
.
这里有四种扩展方法,几乎涵盖了您需要的所有情况。如果没有 - 我希望您能根据这些找出其余部分。
inline fun <reified T> T.toJson(): String = Gson().toJson(this)
inline fun <reified T> String.toObject(): T = Gson().fromJson(this, T::class.java)
inline fun <reified T, K, V> Map<K, V>.toObject(): T = Gson().fromJson(this.toJson(), T::class.java)
// and more classic but less used
fun <T> String.toObject(type: Type): T = Gson().fromJson(this, type)
现在可以像
一样使用了data class SomeClass(val today: Int, val yesterday: Int)
val someClass = SomeClass(3,4)
val json = someClass.toJson() // { "today" : 3,"yesterday" : 4 }
val someClassDesetialized = json.toObject<SomeClass>() // SomeClass(3,4)
val map: Map<String, Int> = mapOf("today" to 2,"yesterday" to 1)
val mapJson= map.toJson() // { "today" : 2,"yesterday" : 1 }
val someClassFromMap = map.toObject<SomeClass, String, Int>() // SomeClass(2,1)
val someClassFromMapJson: SomeClass = mapJson.toObject<SomeClass>().copy(5) // SomeClass(5,1)
...
val data: EchoData<T> = json.toObject()
val data1 = json.toObject<EchoData<T>>()
类似的东西。请注意,Gson lib 使用 Java serialization so it maybe slower and less secure than Kotlin specific kotlinx.serialization 但它不像 kotlinx.serialization 那样处于 prealpha 版本,因此它不易出错且更成熟。
编辑1
这里是如何以非常符合行业标准的方式隐藏转换。
inline fun <reified T> Map<String, Any>.convert(): T = toObject()
然后像
一样使用它map.convert<SomeClass>()
它比将 Type 作为方法参数传递更好。
您必须调整此方法才能在 Java 代码中使用。 Here 解释了如何操作。
编辑2
这是您的应用已修复的架构问题
你的例子中的一些类应该是
class SomeClass {
inline fun <reified T> listen(event: String, callback: (T) -> Unit) {
Emitter.Listener {
Log.e(TAG, "Data ${it[1]}")
if (it.size > 1)
// I don't know what it[1] is so I assume it is map<String, Any> since it was in an original issue.
callback((it[1] as Map<String, Any>).toObject<T, String, Any>())
}.apply{
this@SomeClass.socket.on(event, this)
this@SomeClass.bind(event, this)
}
}
}
当它的使用量现在可以减少到
SomeClass().listen<Message>("someEvent", { message ->
// do some stuff with message
})
这不是从 Map 到 Pojo 的原始转换问题的修复。这是有缺陷的方法的架构修复。
希望对您有所帮助。