【问题标题】:Gson and Serializing an ArrayList of Objects with InheritanceGson 和序列化具有继承的对象的 ArrayList
【发布时间】:2015-07-02 13:17:55
【问题描述】:

我对 Gson 和 Json 很陌生。我有一些简单的事件,我想在 Gson 的帮助下通过 Json 序列化。

注意:Kotlin 中的代码。

public abstract class Event() {
}

public class Move : Event() {
        var from: Point? = null
        var to: Point? = null
    }

    public class Fire : Event() {
        var damage: Int = 0
        var area: ArrayList<Point> = ArrayList(0)
    }

    public class Build : Event() {
        var to: Point? = null
        var type: String = ""
        var owner: String = ""
    }

我通过这种方式坚持这些:

val list: ArrayList<Event>() = ArrayList()
list.add(move)
list.add(fire)
val str = gson.toJson(events)

并且不持久:

val type = object : TypeToken<ArrayList<Event>>(){}.getType()
val eventStr = obj.getString("events")
val events: ArrayList<Event> = gson.fromJson(eventStr, type)

我已经尝试为 Event-class 创建一个序列化器和反序列化器,并通过 registerTypeAdapter 注册它,我还尝试了 RuntimeTypeAdapterFactory,但两者都不会保留取消保留正确类型所需的信息。

例如,RuntimeTypeAdapterFactory 说: “无法反序列化事件,因为它没有定义名为类型的字段”

编辑:这是“适配器”的代码,它是......好吧,改编自另一个 StackOverflow 帖子:

public class Adapter :
            JsonSerializer<Event>,
            JsonDeserializer<Event> {

        final val CLASSNAME = "CLASSNAME"
        final val INSTANCE  = "INSTANCE"

        override fun serialize(src: Event?, typeOfSrc: Type?, context: JsonSerializationContext?): JsonElement? {
            val obj = JsonObject()
            val className = (src as Event).javaClass.getCanonicalName()
            obj.addProperty(CLASSNAME, className)
            val elem = context!!.serialize(src)
            obj.add(INSTANCE, elem)
            return obj
        }

        override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): Event? {
            val jsonObject =  json!!.getAsJsonObject()
            val prim = jsonObject.get(CLASSNAME)
            val className = prim.getAsString()
            val klass = Class.forName(className)
            return context!!.deserialize(jsonObject.get(INSTANCE), klass)
        }
    }

此代码失败并出现 NullPointerException 在线:

val className = prim.getAsString()

【问题讨论】:

  • 我想创建一个自定义反序列化器是要走的路。你能把你写的代码贴出来吗?
  • @RiccardoCiovati 嗨,我添加了一些代码。序列化事件没有任何问题..但是,就像我说的,当我反序列化它们时,信息根本不存在(我打印了一个反序列化的移动事件,它只有“来自”的点数据和“to”)(我也有一个 Point-class 的自定义序列化程序)
  • 傻我。我根本没有为子类注册类型适配器,而只是为事件类注册,这就是问题所在。但是,现在我在线上有一个 StackOverflowError:val elem = context!!.serialize(src)。有什么想法可能导致这种情况吗?
  • 怀疑这是由于(src as Event)。但我不确定如何解决它。
  • 你有堆栈溢出,因为你调用 ????在已经序列化的 src 对象上序列化。你只需调用 ????你的代码递归

标签: java json gson kotlin


【解决方案1】:

你不能这样做。

您所引用的示例并非针对您的案例。它仅在一种情况下有效:如果您注册基本类型(不是类型层次结构)并使用gson.toJson(obj, javaClass&lt;Event&gt;()) 进行序列化。除非您也为事件容器对象编写自定义序列化程序,否则它永远不会适用于数组

通常您需要另一种方法:使用 TypeAdapterFactory 并委托适配器:GSON: serialize/deserialize object of class, that have registered type hierarchy adapter, using ReflectiveTypeAdapterFactory.Adapterhttps://code.google.com/p/google-gson/issues/detail?id=43#c15

我认为这种方法过于复杂,所以如果您的类型很少,最简单的解决方案是两个手动序列化这些类型,通过自定义序列化程序逐个字段,忘记尝试委托为默认值

【讨论】:

  • 感谢您的回答。我通过手动序列化类型来解决它,并且只是为每种类型设置一个单独的 ArrayList。
猜你喜欢
  • 2020-04-16
  • 1970-01-01
  • 2010-10-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多