Kotlin com.google.gson.internal.LinkedTreeMap无法强制转换到我的自定义类

Kotlin com.google.gson.internal.LinkedTreeMap无法强制转换到我的自定义类,kotlin,gson,Kotlin,Gson,我得到: 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: Strin

我得到:

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}")
    }
})
//自定义类
数据类消息(
@序列化名称(“内容”)
val内容:字符串?=null
)
//我的抽象课
抽象类EchoListener{
伴星{
private val TAG=EchoListener::class.java.simpleName
}
已收到摘要(数据:T?)
趣味提交数据(it:任何){
Log.e(标记“Echio data${it}”)
val gson=gson()
val json=gson.toJson(it)
val data:EchoData=gson.fromJson(json,genericType())
Log.e(标记,“转换数据${data.data}”)
onDataReceived(data.data)
}
}
inline fun genericType()=对象:TypeToken(){}.type
上课{
有趣的侦听(事件:字符串,回调:EchoListener){
val listener=Emitter.listener{
Log.e(标记“Data${it[1]}”)
如果(it.size>1)
callback.submitData(it[1])
}
this.socket.on(事件,侦听器)
this.bind(事件、侦听器)
}
}
//主要活动
someClassObj?.listen(“聊天”,对象:EchoListener(){
覆盖已接收的数据(数据:消息?){
Log.e(标记“Message${data}”)
}
})
已编辑

以下是我正在创建的库的链接:

这是示例android应用程序

这可以用一种相当简单的方法来完成。首先,请查看,了解其工作原理,然后将库依赖项添加到app 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)

}
然后在您的
活动中或其他地方:

 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)

你试着用一种非常复杂的方式来使用它。有了它,事情会变得容易得多

这里有四种扩展方法,它们将涵盖您需要的几乎所有情况。如果没有-我希望你能根据这些找出剩下的

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)
inline fun T.toJson():String=Gson().toJson(this)
内联fun String.toObject():T=Gson().fromJson(这个,T::class.java)
内联fun Map.toObject():T=Gson().fromJson(this.toJson(),T::class.java)
//更经典,但使用较少
趣味字符串.toObject(类型:type):T=Gson().fromJson(此类型)
现在你可以像这样使用它了

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>>()
map.convert<SomeClass>()
数据类SomeClass(今天的val:Int,昨天的val:Int)
val someClass=someClass(3,4)
val json=someClass.toJson()/{“今天”:3,“昨天”:4}
val someclassdesetilized=json.toObject()//SomeClass(3,4)
val map:map=mapOf(“今天”到2,“昨天”到1)
val mapJson=map.toJson()/{“今天”:2,“昨天”:1}
val someClassFromMap=map.toObject()//SomeClass(2,1)
val someClassFromMapJson:SomeClass=mapJson.toObject().copy(5)//SomeClass(5,1)
...
val data:EchoData=json.toObject()
val data1=json.toObject()
差不多吧。请注意,Gson lib使用Java,因此它可能比Kotlin-specific更慢、更不安全,但它在prealpha版本中没有kotlinx.serialization,因此它更不容易出现错误,也更成熟

编辑1 下面是如何以行业标准的方式隐藏转换

inline fun <reified T> Map<String, Any>.convert(): T = toObject() 
inline fun Map.convert():T=toObject()
然后像这样使用它

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>>()
map.convert<SomeClass>()
map.convert()
这比将类型作为方法参数传递要好

但是,您必须调整这些方法,使其能够从Java代码中使用。它解释了如何做

编辑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)
            }
        }
    }
class-SomeClass{
内联趣味监听(事件:字符串,回调:(T)->Unit){
发射器.侦听器{
Log.e(标记“Data${it[1]}”)
如果(it.size>1)
//我不知道它[1]是什么,所以我假设它是地图,因为它是原版的。
回调((它[1]作为Map.toObject())
}.申请{
this@SomeClass.socket.on(事件,本)
this@SomeClass.bind(事件,本)
}
}
}
当它的使用现在可以减少到

 SomeClass().listen<Message>("someEvent", { message ->
// do some stuff with message
            })

SomeClass().listen(“someEvent”,{message->
//用信息做一些事情
})
这不是解决从Map到Pojo的原始转换问题的方法。这是对有缺陷方法的架构修复


希望有帮助。

我写了一些东西,比如你想要什么,但是使用(Kotlin团队的序列化库)而不是gson将其转换为JSON,这对你有帮助吗?换句话说,您正在搜索的解决方案是否必须使用gson?@Abed谢谢。它适用于泛型类型吗?当然,它非常有效,我将使用它发布答案。如果您还有任何问题,请随时提问。这不会解决问题。。。序列化和反序列化对于简单场景来说不是问题,当库知道它将要接收的数据类型时。库不知道要转换的数据类型。数据类型由用户提供。请检查提供的github链接。请检查android示例repo。您的权利kotlin序列化库仍在试验中