gson 的多态性 [英] Polymorphism with gson

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

问题描述

我在使用 Gson 反序列化 json 字符串时遇到问题.我收到一系列命令.命令可以是 start 、 stop 、其他一些类型的命令.自然我有多态性,并且启动/停止命令从命令继承.

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.

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

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.

推荐答案

这有点晚了,但我今天必须做完全相同的事情.因此,根据我的研究和使用 gson-2.0 时,您真的不想使用 registerTypeHierarchyAdapter 方法,而是更普通的 registerTypeAdapter.并且您当然不需要为派生类做instanceofs 或编写适配器:只需一个适配器用于基类或接口,当然前提是您对派生类的默认序列化感到满意.无论如何,这是代码(已删除包和导入)(也可在 github 中找到):

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

两个派生类,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:

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

和测试类:

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 时,您会得到以下输出:

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)

我实际上也使用 registerTypeHierarchyAdapter 方法完成了上述操作,但这似乎需要实现自定义 DogAdapter 和 CatAdapter 序列化器/解串器类,当您想添加另一个时,这些类很难维护字段到狗或猫.

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天全站免登陆