代码之家  ›  专栏  ›  技术社区  ›  alexm

如何正确地对kotlin中的复杂对象进行Gson序列化/反序列化?

  •  2
  • alexm  · 技术社区  · 6 年前

    JSON字符串有以下字段:

    action=surveyEventName
    EventObject= serialized Event object (So in this field I want to serialize an object with Gson.
    

    我遇到的问题是,当我尝试序列化事件对象时,会得到一个ANR。所以,我认为我在设置Gson序列化方面可能做错了什么。

    事件类的定义方式如下:

    class Event {
    
    private var mActionName = ""
    private var mId = ""
    private lateinit var mConditions: MutableList<(Unit) -> Boolean>
    private lateinit var mActions: MutableList<(Unit) -> Boolean>
    
    fun getActionName(): String {
        return this.mActionName
    }
    
    fun setActionName(actionName: String) {
        this.mActionName = actionName
    }
    
    fun getId(): String {
        return this.mId
    }
    
    fun setId(id: String) {
        this.mId = id
    }
    
    fun addSingleCondition(condition: (Unit) -> Boolean) {
        if(::mConditions.isInitialized) {
            mConditions.add(condition)
        } else {
            mConditions = mutableListOf(condition)
        }
    }
    
    fun addSingleAction(action: (Unit) -> Boolean) {
        if(::mActions.isInitialized) {
            mActions.add(action)
        } else {
            mActions = mutableListOf(action)
        }
    }
    
    companion object {
        fun serializeEventList(event: List<Event>): String {
            return Gson().toJson(event) // ANR HERE!
        }
    
        fun deserializeEventList(jsonString: String): MutableList<Event> {
            return Gson().fromJson(jsonString,
                    object : TypeToken<List<Event>>() {}.type)
        }
    }
    }
    

    因此,我希望我的最终JSON(如上所述)具有一个动作标记和一个事件对象的序列化列表。我的问题是,当我尝试序列化列表时,会得到一个ANR。

    这是我的测试块:

    //TESTBLOCK
    fun testEvent() {
        //create test event
        val event = Event()
        event.setId("1")
        event.setActionName("testtag")
        event.addSingleCondition { testCondition1() }
        event.addSingleCondition { testCondition2() }
        event.addSingleAction { testAction1() }
        event.addSingleAction { testAction2() }
        val events = listOf(event)
        //create test JSON
        val jsonObject = JSONObject()
        jsonObject.put("tagfield", "testtag")
        val serializedObjectString = event.serializeEventList(events) 
        jsonObject.put("eventobjectfield", serializedObjectString)
    
    }
    

    之后,我反序列化JSON eventobjectfield以再次使用事件对象,但当我尝试序列化时,我得到了ANR。

    由于我添加到事件对象的lambda,我不确定Gson是否工作不正常。我可能做错了什么?

    1 回复  |  直到 6 年前
        1
  •  0
  •   alexm    5 年前

    我在一些实现中遇到过这个问题,直到我意识到如果您在使用Gson时保持谨慎,它会更好地工作。我发现在我的代码中有两个不太好用的地方:

    1) lateinit变量:由于某种原因,Gson在解析带有这些变量的类时会挂起。 2) 使用重写值继承成员变量或属性:基本上,

    如果我重写继承的值,Gson会抱怨我定义了两个同名变量,示例如下:

    open class Person() {
        var id = 0
        var name = ""
        var age = 0
    }
    
    class AdultPerson() : Person() {
        override var age = 18
    }
    

    Gson会抱怨对象有两个同名年龄的变量。为了解决这个问题,我必须在构造函数块或init块中更改age的默认值,以不重写变量。

    所以,考虑到这两件事,我设法让Gson将我的对象转换为字符串,即使它们有复杂的继承、集合或包含集合变量的类。

    我已经优化了以前的Gson解析器,使其能够与其他类一起工作,到目前为止,它工作得很好:

    GsonParser。千吨级

    object GsonParser {
        inline fun <reified T> toJson(src: T): String {
            return Gson().toJson(src)
        }
    
        inline fun <reified T> fromJson(src: String): T {
            val type = object : TypeToken<T>() {}.type
            return Gson().fromJson(src, type)
        }
    }
    

    希望有帮助!