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?
答案 0 :(得分:3)
要反序列化您的JSON,您需要为Recursive接口提供自定义反序列化器。在这种类中,您需要检查您的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 []}]}]
答案 1 :(得分:1)
很抱歉回复得太晚了(因为这个问题已经回答了)。但我想我可以给这个问题2美分。
正如@Parobay之前所说,您可以添加一个特殊的{"type": "complex"}
参数,以便知道您要反序列化哪个类。但如前所述,您必须将所有数据移至{"instance": {}}
子对象,因为您必须手动控制在大switch
中创建的实例。
您可以使用TypeFactory
类来更好地处理这种情况。更准确地说,有一个特殊的工厂(目前没有与Gson捆绑在一起)应该称为RuntimeTypeAdapterFactory
。复制有关此课程的文档:
调整运行时类型可能与其声明不同的值 类型。当字段的类型与字段类型不同时,这是必需的 GSON应该在反序列化该字段时创建。例如, 考虑以下类型:
{ abstract class Shape { int x; int y; } class Circle extends Shape { int radius; } class Rectangle extends Shape { int width; int height; } class Diamond extends Shape { int width; int height; } class Drawing { Shape bottomShape; Shape topShape; } }如果没有其他类型信息,序列化的JSON是不明确的。此图中的底部形状是a 长方形还是钻石?
{ { "bottomShape": { "width": 10, "height": 5, "x": 0, "y": 0 }, "topShape": { "radius": 2, "x": 4, "y": 1 } }}此类通过向序列化JSON添加类型信息并遵守该类型来解决此问题 反序列化JSON时的信息:{ { "bottomShape": { "type": "Diamond", "width": 10, "height": 5, "x": 0, "y": 0 }, "topShape": { "type": "Circle", "radius": 2, "x": 4, "y": 1 } }}类型字段名称({@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();
瞧,你有对象的自动(反)序列化。我创建了这个工厂的变体而不是期望type
参数,尝试通过运行自定义正则表达式来发现什么类型的对象(这样你就可以避免创建额外的参数,或者当你没有完全控制API。)
在这里,我给出了两个来源链接: