[英]Deserialize recursive polymorphic class in GSON
class Complex implements Recursive {
Map<String, Recursive> map;
...
}
class Simple implements Recursive { ... }
我如何反序列化此json:
{
"type" : "complex",
"map" : {
"a" : {
"type" : "simple"
},
"b" : {
"type" : "complex",
"map" : {
"ba" : {
"type" : "simple"
}
}
}
}
使用Google GSON?
要反序列化JSON,您需要为递归接口使用自定义反序列化器。 在这种类中,您需要检查JSON并确定要实例化为JSON本身的type字段的类。 在这里,您有一个我为您编写的示例基本解串器。
当然,管理边界事件可以得到改善(例如,如果您没有类型字段,会发生什么情况?)。
package stackoverflow.questions;
import java.lang.reflect.Type;
import java.util.*;
import stackoverflow.questions.Q20254329.*;
import com.google.gson.*;
import com.google.gson.reflect.TypeToken;
public class Q20327670 {
static class Complex implements Recursive {
Map<String, Recursive> map;
@Override
public String toString() {
return "Complex [map=" + map + "]";
}
}
static class Simple implements Recursive {
@Override
public String toString() {
return "Simple []";
}
}
public static class RecursiveDeserializer implements JsonDeserializer<Recursive> {
public Recursive deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
Recursive r = null;
if (json == null)
r = null;
else {
JsonElement t = json.getAsJsonObject().get("type");
String type = null;
if (t != null) {
type = t.getAsString();
switch (type) {
case "complex": {
Complex c = new Complex();
JsonElement e = json.getAsJsonObject().get("map");
if (e != null) {
Type mapType = new TypeToken<Map<String, Recursive>>() {}.getType();
c.map = context.deserialize(e, mapType);
}
r = c;
break;
}
case "simple": {
r = new Simple();
break;
}
// remember to manage default..
}
}
}
return r;
}
}
public static void main(String[] args) {
String json = " { " +
" \"type\" : \"complex\", " +
" \"map\" : { " +
" \"a\" : { " +
" \"type\" : \"simple\" " +
" }, " +
" \"b\" : { " +
" \"type\" : \"complex\", " +
" \"map\" : { " +
" \"ba\" : { " +
" \"type\" : \"simple\" " +
" } " +
" } " +
" } " +
" } } ";
GsonBuilder gb = new GsonBuilder();
gb.registerTypeAdapter(Recursive.class, new RecursiveDeserializer());
Gson gson = gb.create();
Recursive r = gson.fromJson(json, Recursive.class);
System.out.println(r);
}
}
这是我的代码的结果:
Complex [map={a=Simple [], b=Complex [map={ba=Simple []}]}]
抱歉回复太晚(因为此问题已得到回答)。 但是我想我可以给这个问题2美分。
正如@Parobay所说的那样,您可以添加一个特殊的{"type": "complex"}
参数以了解要反序列化的类。 但是如前所述,您必须将所有数据移动到一个{"instance": {}}
子对象,该子对象感觉很笨拙,因为您必须手动控制在big switch
创建的实例。
您可以改用TypeFactory
类来更好地处理这种情况。 更确切地说,有一个特殊的工厂(该工厂目前未与Gson捆绑在一起,应该将其命名为RuntimeTypeAdapterFactory
。 复制有关该类的文档说明:
适应其运行时类型可能不同于其声明类型的值。 当字段的类型与GSON反序列化该字段时应创建的类型不同时,这是必需的。 例如,考虑以下类型:
{\n 抽象类Shape {\n int x;\n 诠释\n }\n 类Circle扩展Shape {\n 整数半径\n }\n 矩形扩展Shape的类{\n 整数宽度\n 整数高度\n }\n 钻石级延伸形状{\n 整数宽度\n 整数高度\n }\n 类图{\n 形状bottomShape;\n 形状topShape;\n }}如果没有其他类型信息,则序列化的JSON不明确。 该图中的底部形状是矩形还是菱形?
{\n {\n “ bottomShape”:{\n “宽度”:10,\n “身高”:5\n “ x”:0,\n “ y”:0\n },\n “ topShape”:{\n “半径”:2\n “ x”:4\n “ y”:1\n }\n }}此类通过将类型信息添加到序列化的JSON并在反序列化JSON时保留该类型信息来解决此问题:{\n {\n “ bottomShape”:{\n “ type”:“ Diamond”,\n “宽度”:10,\n “身高”:5\n “ x”:0,\n “ y”:0\n },\n “ topShape”:{\n “ type”:“ Circle”,\n “半径”:2\n “ x”:4\n “ y”:1\n }\n }}类型字段名称({@code“ type”})和类型标签({@code“ Rectangle”})都是可配置的。
因此,您只需要使用以下命令创建Gson对象:
RuntimeTypeAdapter<Shape> shapeAdapter
= RuntimeTypeAdapter.of(Shape.class, "type")
.registerSubtype(Rectangle.class, "Rectangle");
Gson gson = new GsonBuilder()
.registerTypeAdapter(Shape.class, shapeAdapter)
.create();
而且,您可以自动(反)序列化对象。 我创建了这个Factory的变体,而不是期望type
参数,而是尝试通过运行自定义正则表达式来发现什么样的对象(这样可以避免创建额外的参数,或者当您没有完全控制权时API)。
在这里,我为您提供了两个带有来源的链接:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.