使用帶繼承的 GSON
GSON 不支援繼承我們的框。假設我們有以下類層次結構:
public class BaseClass {
int a;
public int getInt() {
return a;
}
}
public class DerivedClass1 extends BaseClass {
int b;
@Override
public int getInt() {
return b;
}
}
public class DerivedClass2 extends BaseClass {
int c;
@Override
public int getInt() {
return c;
}
}
現在我們想要將 DerivedClass1
的一個例項序列化為一個 json 字串
DerivedClass1 derivedClass1 = new DerivedClass1();
derivedClass1.b = 5;
derivedClass1.a = 10;
Gson gson = new Gson();
String derivedClass1Json = gson.toJson(derivedClass1);
現在,在另一個地方,我們收到這個 json 字串並想要反序列化它 - 但在編譯時我們只知道它應該是 BaseClass
的一個例項:
BaseClass maybeDerivedClass1 = gson.fromJson(derivedClass1Json, BaseClass.class);
System.out.println(maybeDerivedClass1.getInt());
但 GSON 不知道 derivedClass1Json
最初是 DerivedClass1
的一個例項,所以這將列印出來 10。
怎麼解決這個?
你需要建立自己的 JsonDeserializer
來處理這種情況。解決方案不是很乾淨,但我無法想出更好的解決方案。
首先,將以下欄位新增到基類
@SerializedName("type")
private String typeName;
並在基類建構函式中初始化它
public BaseClass() {
typeName = getClass().getName();
}
現在新增以下類:
public class JsonDeserializerWithInheritance<T> implements JsonDeserializer<T> {
@Override
public T deserialize(
JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
JsonObject jsonObject = json.getAsJsonObject();
JsonPrimitive classNamePrimitive = (JsonPrimitive) jsonObject.get("type");
String className = classNamePrimitive.getAsString();
Class<?> clazz;
try {
clazz = Class.forName(className);
} catch (ClassNotFoundException e) {
throw new JsonParseException(e.getMessage());
}
return context.deserialize(jsonObject, clazz);
}
}
剩下要做的就是搞定一切 -
GsonBuilder builder = new GsonBuilder();
builder
.registerTypeAdapter(BaseClass.class, new JsonDeserializerWithInheritance<BaseClass>());
Gson gson = builder.create();
現在,執行以下程式碼 -
DerivedClass1 derivedClass1 = new DerivedClass1();
derivedClass1.b = 5;
derivedClass1.a = 10;
String derivedClass1Json = gson.toJson(derivedClass1);
BaseClass maybeDerivedClass1 = gson.fromJson(derivedClass1Json, BaseClass.class);
System.out.println(maybeDerivedClass1.getInt());
將列印 5。