Gson и сериализация массива объектов с наследованием

Я очень новичок в Gson and Json. У меня есть простые события, которые я хочу сериализовать через Json с помощью Gson.

Примечание: Код в Котлине.

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 и зарегистрировать его через registerTypeAdapter, и я также попробовал RuntimeTypeAdapterFactory, но не будет сохраняться информация, необходимая для того, чтобы отменить правильный тип.

Например, RuntimeTypeAdapterFactory говорит: «не может десериализовать событие, потому что оно не определяет поле с именем type»

EDIT : Вот код для «Адаптера», который был … ну, адаптирован из другого сообщения 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() 

Вы не можете этого сделать.

Пример, на который вы ссылаетесь, не предназначен для вашего случая. Он работает только в одном случае: если вы регистрируете базовый тип (не иерархию типов) и сериализуете с помощью gson.toJson(obj, javaClass<Event>()) . Он никогда не будет работать для массива, за исключением того, что вы пишете собственный сериализатор для объектов событий

Обычно вам нужен другой подход: используйте адаптеры TypeAdapterFactory и делегат: GSON: сериализовать / десериализовать объект класса, который имеет зарегистрированный адаптер иерархии типов, используя ReflectiveTypeAdapterFactory.Adapter и https://code.google.com/p/google-gson/issues / деталь? ID = 43 # c15

Я считаю, что этот подход слишком сложный, поэтому, если у вас есть несколько типов, самым простым решением является сериализация этих типов вручную, поле за полем с помощью настраиваемого сериализатора и забыть о попытках делегирования по умолчанию