与gson的多态性 [英] Polymorphism with gson

查看:120
本文介绍了与gson的多态性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用Gson反序列化json字符串时出现问题。
我收到一组命令。该命令可以是启动,停止或其他类型的命令。当然,我有多态性,并从命令继承启动/停止命令。



如何使用gson将其序列化回正确的命令对象?



似乎我只得到基本类型,这是声明的类型,从来没有运行时类型。

解决方案

这有点晚,但我必须做到今天同样的事情。因此,基于我的研究和使用gson-2.0时,您确实不想使用 registerTypeHierarchyAdapter 方法,而是使用更普通的 registerTypeAdapter 。您当然不需要执行 instanceofs 或为派生类编写适配器:只有一个适用于基类或接口的适配器,当然提供您对派生类的默认序列化感到满意。无论如何,这里是代码(已删除软件包和导入)(也可在 github 中获得):



基类(我的例子中的接口):

pre $ public c ++ public interface IAnimal { public String sound(); }

两个派生类Cat:

  public class Cat实现IAnimal {

public String name;

public Cat(String name){
super();
this.name = name;
}

@Override
public String sound(){
return name +:\meaow \;
};
}

和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;

$ b @Override
public String sound(){
return name +:\bark\(ferocity level:+ ferocity + );


IAnimalAdapter:

 公共类IAnimalAdapter实现JsonSerializer< IAnimal>中JsonDeserializer< IAnimal> {

私有静态最后字符串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);
返回retValue;
}

@覆盖
公共IAnimal反序列化(JsonElement JSON,类型typeOfT,
JsonDeserializationContext上下文)抛出JsonParseException {
的JSONObject的JSONObject = json.getAsJsonObject( );
JsonPrimitive prim =(JsonPrimitive)jsonObject.get(CLASSNAME);
String className = prim.getAsString();

Class<?> klass = null;
尝试{
klass = Class.forName(className);
} catch(ClassNotFoundException e){
e.printStackTrace();
抛出新的JsonParseException(e.getMessage());
}
return context.deserialize(jsonObject.get(INSTANCE),klass);
}
}

和Test类:

  public class Test {b 
$ b public static void main(String [] args){
IAnimal animals [] =新的猫咪[] {新猫(猫),新狗(布鲁图斯,5)};
Gson gsonExt = null;
{
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(IAnimal.class,new IAnimalAdapter());
gsonExt = builder.create();

(动物,动物){
String animalJson = gsonExt.toJson(animal,IAnimal.class);
System.out.println(使用自定义序列化器序列化:+ animalJson);
IAnimal animal2 = gsonExt.fromJson(animalJson,IAnimal.class);
System.out.println(animal2.sound());



$ / code>

运行测试时: :main获得以下输出:

 用自定义序列化程序序列化:
{CLASSNAME:com。 $b $ b Kitty:使用自定义序列化器序列化的meaow

{CLASSNAME:com.synelixis.caches.viz.json.playground.plainAdapter.Dog,I​​NSTANCE:{name:Brutus,ferocity:5}}
布鲁图斯:bark(恶意程度级别:5)

我已经使用 registerTypeHierarchyAdapter 方法,但似乎需要实现自定义的DogAdapter和CatAdapter序列化器/反序列化器类,这些类很难保持任何时候想要向Dog或Cat添加另一个字段。


I have a problem deserializing a json string with Gson. I receive an array of commands. The command can be start, stop , some other type of command. Naturally I have polymorphism, and start/stop command inherit from command.

How can I serialize it back to the correct command object using gson?

Seems that I get only the base type, that is the declared type and never the runtime type.

解决方案

This is a bit late but I had to do exactly the same thing today. So, based on my research and when using gson-2.0 you really don't want to use the registerTypeHierarchyAdapter method, but rather the more mundane registerTypeAdapter. And you certainly don't need to do instanceofs or write adapters for the derived classes: just one adapter for the base class or interface, provided of course that you are happy with the default serialization of the derived classes. Anyway, here's the code (package and imports removed) (also available in github):

The base class (interface in my case):

public interface IAnimal { public String sound(); }

The two derived classes, 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 + ")";
    }
}

The 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);
    }
}

And the Test class:

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());
        }
    }
}

When you run the Test::main you get the following output:

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)

I've actually done the above using the registerTypeHierarchyAdapter method too, but that seemed to require implementing custom DogAdapter and CatAdapter serializer/deserializer classes which are a pain to maintain any time you want to add another field to Dog or to Cat.

这篇关于与gson的多态性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆