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"
}
}
}
}
使用谷歌GSON?
要反序列化 JSON,您需要为递归接口自定义反序列化程序。在这种类中,您需要检查 JSON 并决定将哪种类实例化为 JSON 本身中的类型字段。这里有一个我为你写的基本反序列化程序的例子。
当然,可以改进管理临界情况(例如,如果您没有类型字段会发生什么?
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": {}}
子对象,这感觉很奇怪,因为您必须手动控制在大switch
中创建的实例。
您可以改用 TypeFactory
类来更好地处理这种情况。更准确地说,有一个特殊的工厂(目前没有与 Gson 捆绑在一起,应该(叫做 RuntimeTypeAdapterFactory
.复制有关此类的文档说明:
调整运行时类型可能与其声明不同的值 类型。当字段的类型与 GSON 应在反序列化该字段时创建。例如 考虑以下类型:
{ 抽象类形状 { 整数 x; 国际 y; } 类 圆 延伸 形状 { 整数半径; } 类 矩形 扩展形状 { 整数宽度; 整数高度; } 类 钻石延伸 形状 { 整数宽度; 整数高度; } 类绘图 { 形状底部形状; 形状顶部形状; } } 如果没有其他类型信息,序列化的 JSON 是不明确的。此图中的底部形状是 矩形还是菱形?
{ { "底部形状":{ "宽度": 10, "高度": 5, "x": 0, "y": 0 }, "topShape": { "半径": 2, "x": 4, "y":1 } }}此类通过向序列化的 JSON 添加类型信息并遵循该类型来解决此问题 反序列化 JSON 时的信息:{ { "底部形状":{ "类型": "钻石", "宽度": 10, "高度": 5, "x": 0, "y": 0 }, "topShape": { "类型": "圆圈", "半径": 2, "x": 4, "y":1 } }}类型字段名称({@code "type"}( 和类型标签({@code "矩形"}( 都是可配置的。
因此,您只需使用以下命令创建 Gson 对象:
RuntimeTypeAdapter<Shape> shapeAdapter
= RuntimeTypeAdapter.of(Shape.class, "type")
.registerSubtype(Rectangle.class, "Rectangle");
Gson gson = new GsonBuilder()
.registerTypeAdapter(Shape.class, shapeAdapter)
.create();
瞧,你有对象的自动(反(序列化。我创建了这个工厂的一个变体,它不期望一个type
参数,而是尝试通过运行自定义正则表达式来发现什么样的对象(这样你可以避免创建额外的参数,或者当你没有完全控制 API 时(。
在这里,我为您提供两个来源的链接:
- 原始运行时类型适配器工厂源代码。
- 我的修改运行时正则表达式类型适配器出厂源代码。