我在使用Gson反序列化json字符串时遇到问题。我收到一系列命令。该命令可以是start,stop或其他类型的命令。我自然具有多态性,并且start / stop命令从command继承。
如何使用gson将其序列化回正确的命令对象?
似乎我只获得基本类型,即声明的类型,而从未获得运行时类型。
根据我的研究以及使用gson-2.0时,你确实不想使用registerTypeHierarchyAdapter方法,而是更平凡的registerTypeAdapter。而且,你当然不需要为派生类做instanceofs或编写适配器:只为基类或接口提供一个适配器,当然,你对派生类的默认序列化感到满意。无论如何,这是代码(删除了打包和导入)(也可以在github中找到):
基类(在我的情况下为接口):
public interface IAnimal { public String sound(); }
这两个派生类Cat:
public class Cat implements IAnimal { public String name; public Cat(String name) { super(); this.name = name; } @Override public String sound() { return name + " : \"meaow\""; }; }
And Dog:
public class Dog implements IAnimal { public String name; public int ferocity; public Dog(String name, int ferocity) { super(); this.name = name; this.ferocity = ferocity; } @Override public String sound() { return name + " : \"bark\" (ferocity level:" + ferocity + ")"; } }
IAnimalAdapter:
public class IAnimalAdapter implements JsonSerializer<IAnimal>, JsonDeserializer<IAnimal>{ private static final String CLASSNAME = "CLASSNAME"; private static final String INSTANCE = "INSTANCE"; @Override public JsonElement serialize(IAnimal src, Type typeOfSrc, JsonSerializationContext context) { JsonObject retValue = new JsonObject(); String className = src.getClass().getName(); retValue.addProperty(CLASSNAME, className); JsonElement elem = context.serialize(src); retValue.add(INSTANCE, elem); return retValue; } @Override public IAnimal deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { JsonObject jsonObject = json.getAsJsonObject(); JsonPrimitive prim = (JsonPrimitive) jsonObject.get(CLASSNAME); String className = prim.getAsString(); Class<?> klass = null; try { klass = Class.forName(className); } catch (ClassNotFoundException e) { e.printStackTrace(); throw new JsonParseException(e.getMessage()); } return context.deserialize(jsonObject.get(INSTANCE), klass); } }
和测试类:
public class Test { public static void main(String[] args) { IAnimal animals[] = new IAnimal[]{new Cat("Kitty"), new Dog("Brutus", 5)}; Gson gsonExt = null; { GsonBuilder builder = new GsonBuilder(); builder.registerTypeAdapter(IAnimal.class, new IAnimalAdapter()); gsonExt = builder.create(); } for (IAnimal animal : animals) { String animalJson = gsonExt.toJson(animal, IAnimal.class); System.out.println("serialized with the custom serializer:" + animalJson); IAnimal animal2 = gsonExt.fromJson(animalJson, IAnimal.class); System.out.println(animal2.sound()); } } }
当运行Test :: main时,将得到以下输出:
serialized with the custom serializer: {"CLASSNAME":"com.synelixis.caches.viz.json.playground.plainAdapter.Cat","INSTANCE":{"name":"Kitty"}} Kitty : "meaow" serialized with the custom serializer: {"CLASSNAME":"com.synelixis.caches.viz.json.playground.plainAdapter.Dog","INSTANCE":{"name":"Brutus","ferocity":5}} Brutus : "bark" (ferocity level:5)
我实际上也使用registerTypeHierarchyAdapter方法完成了上述操作,但这似乎需要实现自定义的DogAdapter和CatAdapter序列化器/反序列化器类,这在你想向Dog或Cat添加另一个字段时很难维护。