我在用gson反序列化JSON字符串时遇到问题。
我收到一系列命令。命令可以是启动、停止或其他类型的命令。当然,我有多态性,启动/停止命令继承自命令。
如何使用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\"";
};
}
还有狗:
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添加另一个字段时,这些类很难维护。