我得到:
com.google.gson.internal.LinkedTreeMap cannot be cast to Message class
我想将任何类型的对象转换为我的自定义类。我正在尝试gson将对象转换为JSON,然后将JSON字符串转换为我的Message
类。
我使用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}")
}
})
已编辑
以下是我正在创建的库的链接: Github repo
这是示例Android应用程序 Android Github Repo
答案 0 :(得分:1)
可以使用kotlinx.serialization以一种非常简单的方式完成此操作。首先,请参见exmple了解其工作原理,然后将库依赖项添加到应用程序build.gradle:
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.13.0"
请注意,要能够在Kotlin代码中使用Kotlin序列化库,请确保您的Kotlin编译器版本为1.3.30
或更高版本。
现在,您需要使用@Serializable
注释注释要序列化/反序列化的所有类,并确保要从kotlinx.serialization.Serializable
进行导入。
在为类加上注释后,编译器将为每个类自动以Java字节代码serializer()
生成一个静态函数,我们将调用该函数对该类进行序列化和反序列化。
现在要实现通用的序列化/反序列化功能,请将此文件添加到您的项目中:
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
类:
import kotlinx.serialization.Serializable
@Serializable
data class Reciter(
val id: String,
val name: String,
val servers: String
)
然后在您的Activity
或其他位置:
val reciter = Reciter("A123", "ABCD", "https://stackoverflow.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://stackoverflow.com"),
Reciter("B456", "F.abc", "https://stackoverflow.com"),
Reciter("M568", "NDK", "https://stackoverflow.com")
)
val json2 = SerializationManager.serializeList(recitersList,Reciter.serializer().list)
答案 1 :(得分:1)
您尝试以非常复杂的方式使用它。使用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,因此它可能比Kotlin特定的kotlinx.serialization慢且安全性低,但是它没有像kotlinx.serialization那样处于prealpha版本,因此它更不容易出错且更成熟。 >
这是如何以行业标准的方式隐藏转换的方法。
inline fun <reified T> Map<String, Any>.convert(): T = toObject()
然后像使用它
map.convert<SomeClass>()
它比传递Type as方法参数更好。
您将不得不调整此方法以从Java代码中使用。 Here说明了操作方法。
这是您的应用已解决的体系结构问题
您示例中的SomeClass应该是
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的原始转换问题的解决方案。这是有缺陷的方法的体系结构修复。
希望有帮助。