我尝试使用 gson 库来反序列化发送给我的对象流。在我见过的所有示例中,当调用 fromJson 方法时,我们已经知道我们期望拥有的对象类型。
就我而言,我收到了一系列不同的对象,我想知道在反序列化对象之前了解对象类别的最佳方法。
{ A : {...}, B : { B1 : {...}, B2 : {...} }, C : {...} }
在这个例子中,我想知道有 3 个对象已发送给我:A.class、B.class 和 C.class
谢谢
是的,我也偶然发现了这个问题。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;
}
}
如果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();