4

我尝试使用 gson 库来反序列化发送给我的对象流。在我见过的所有示例中,当调用 fromJson 方法时,我们已经知道我们期望拥有的对象类型。

就我而言,我收到了一系列不同的对象,我想知道在反序列化对象之前了解对象类别的最佳方法。

{ A : {...}, B : { B1 : {...}, B2 : {...} }, C : {...} }

在这个例子中,我想知道有 3 个对象已发送给我:A.class、B.class 和 C.class

谢谢

4

3 回答 3

6

该文档包含使用任意类或两次传递的反序列化示例(首先是集合中的一般反序列化,然后是内容反序列化)。

这个例子看起来和你需要的完全一样。你可以调整它来使用

JsonObject obj = parser.parse(json).getAsJsonObject();

获取 aJsonObject而不是数组,以便您可以迭代所有属性(使用entrySeta = gson.fromJson(myjsonelement, A.class); )并通过简单地将名称映射到类来根据名称 ( ) 进行反序列化。

于 2012-06-25T14:39:57.973 回答
2

是的,我也偶然发现了这个问题。gson 无法确定字段值的实际类别。它只是尝试实例化用于定义字段的类。不用说,这往往不是我们想要的。所以如果你有,说

class C {
    private A a;
    private A c;
}

class B extends A {
}

然后在运行时你

C c;
c.a = new B();
c.c = new B();

反序列化后你得到的是

c.a.getClass()==A.class;
c.b.getClass()==A.class;

所以你必须明确指定子类。这是一个对 gson 友好的包装类。

public class S<T> {
    private String objectClass; 
    private String rawObjectRepresentation;
    // Gson needs no args constructor
    public S() {
    }

    public S(T obj) {
        objectClass = obj.getClass().getName();
        rawObjectRepresentation = getGson().toJson(obj);
    }

    @SuppressWarnings("unchecked")
    public T extract() throws ClassNotFoundException {
        final Class<?> clazz = Class.forName(objectClass);
        return (T)getGson().fromJson(rawObjectRepresentation, clazz);
    }

    private Gson getGson() {
        return new GsonBuilder().create();
    }

    @Override
    public String toString() {
        return "type:"+objectClass;
    }
}
于 2012-06-25T14:55:52.133 回答
2

如果json对象上有一个字段可以用来标识需要使用的子类,那么可以使用Gson on Fire:https ://github.com/julman99/gson-fire

它有一个称为类型选择器的功能,可以完全满足您的需求。

想象一个基类和两个子类 A 和 B,那么代码将如下所示:

GsonFireBuilder builder = new GsonFireBuilder()
    .registerTypeSelector(Base.class, new TypeSelector<Base>() {
        @Override
        public Class<? extends Base> getClassForElement(JsonElement readElement) {
            String kind = readElement.getAsJsonObject().get("kind").getAsString();
            if(kind.equals("a")){
                return A.class; //This will cause Gson to deserialize the json mapping to A
            } else if(kind.equals("b")) {
                return B.class; //This will cause Gson to deserialize the json mapping to B
            } else {
                return null; //returning null will trigger Gson's default behavior
            }
        }
    });
Gson gson = builder.createGson();
于 2014-02-27T17:34:34.410 回答