13

我应该如何反序列化以下 JSON 以跳过根元素并仅解析此 JSON 的内部部分。我想避免创建额外的 3rd class Root,它只包括MapWrapper字段。

{
    "root": {
        "language": "en",
        "map": {
            "k1": {
                "name": "n1",
            },
            "k2": {
                "name": "n2",
            }
        }
    }
}

所以我只想有这两个类:

class MapWrapper {
    private String language;
    private Map<String, MyMapEntry> map;
}

class MyMapEntry {
    String name;
}
4

6 回答 6

10

您可以GSON为此使用库。

下面的代码将解决您的问题。

public class ConvertJsonToObject {

    private static Gson gson = new GsonBuilder().create();

    public static final <T> T getFromJSON(String json, Class<T> clazz) {
        return gson.fromJson(json, clazz);
    }

    public static final <T> String toJSON(T clazz) {
        return gson.toJson(clazz);
    }
}

String json; // your jsonString
Map<String,Object> r = ConvertJsonToObject.getFromJSON(json,Map.class);
String innerJson = ConvertJsonToObject.toJson(r.get("root"));
MapWrapper _r = ConvertJsonToObject.getFromJSON(innerJson,MapWrapper.class);
于 2012-08-17T11:16:02.683 回答
3

考虑以下 JSON:

{"authorization":{"username":"userabc", "password":"passabc"}}

此 JSON 的 DTO 没有根元素

public class Authorization {
    private String username;
    private String password;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    // Add a container for the root element
    public static class Container {
        public Authorization authorization;
    }
}

使用以下方法从/到 JSON 转换(您可以将其保留在 DTO 或其他一些帮助类中)

public String toJson(Authorization authorization) {
    Gson gson = new Gson();
    Authorization.Container container = new Authorization.Container();
    container.authorization = authorization;
    return gson.toJson(container);
}

public Authorization fromJson(String json) {
    Gson gson = new Gson();
    Authorization.Container container = gson.fromJson(json, Authorization.Container.class);
    return container.authorization;
}
于 2015-10-13T19:49:49.017 回答
2

这是一次完成的最佳代码。

MapWrapper班级

public class MapWrapper {
    private String language;
    private Map<String, MyMapEntry> map;

    public MapWrapper(String language, Map<String, MyMapEntry> map) {
        this.language = language;
        this.map = map;
    }
}

MyMapEntry班级

public class MyMapEntry {

    String name;

    public MyMapEntry(String name) {
        this.name = name;
    }
}

自定义反序列化器

public class MyDeserialiser  implements JsonDeserializer<MapWrapper>
{

    @Override
    public MapWrapper deserialize(JsonElement json, Type typeOfT,
        JsonDeserializationContext ctx) throws JsonParseException {

        JsonObject _global = json.getAsJsonObject();
        _global = _global.get("root").getAsJsonObject();

        JsonPrimitive lang = (JsonPrimitive) _global.get("language");
        JsonElement map = _global.get("map");
        Map<String, MyMapEntry> inMap = new LinkedHashMap<String, MyMapEntry>();
        for (Entry<String, JsonElement> entry : map.getAsJsonObject()
                .entrySet()) {
            MyMapEntry _m = new MyMapEntry(entry.getValue().toString());
            inMap.put(entry.getKey(), _m);
        }
        return new MapWrapper(lang.getAsString(), inMap);
    }   
}

向 GSON 注册

new GsonBuilder().registerTypeAdapter(MapWrapper.class,new MyDeserialiser()).create()

现在使用以下代码反序列化

String json; // your jsonString
MapWrapper result = ConvertJsonToObject.getFromJSON(json,MapWrapper.class);
于 2012-08-17T11:51:56.740 回答
2

我的回答迟到了。

一旦我们解析了 Json,容器总是会成为 JsonElement 的 JsonObject 子类。因此,如果我们想跳过它,我们只需要将它转换为它的子类并获取包含我们内部类的字段。

    String response = ....;

    Gson gson = new Gson();

    JsonParser p = new JsonParser();
    JsonElement jsonContainer = p.parse(response);
    JsonElement jsonQuery = ((JsonObject) jsonContainer).get("query");

    MyQuery query = gson.fromJson(jsonQuery, MyQuery.class);

注意:JsonObject 和 JSONObject 是不同的类(使用 com.google.Json 导入)。

您可以更概括这个答案,这样您就不需要知道内部类的名称。您可以通过简单地获取容器对象的唯一字段来做到这一点。但是,除了启动迭代器之外,我认为没有其他方法可以做到这一点,我看不到 getValue(atIndex) 方法,而且我认为启动迭代器可能比简单地按名称查找字段效率低(但可能是错误的)。

迭代器方法如下所示:

    JsonElement jsonQuery = ((JsonObject) jsonContainer).entrySet().iterator()
                            .next().getValue();
于 2016-08-26T20:03:55.393 回答
0

您可以将其反序列化为Map<String, MapWrapper>.

于 2012-08-17T10:53:44.823 回答
0

受到 Gustav Carlson 想法的启发,我决定将其扩展为具体示例。这是一个测试将此 JSON 解析为 Map 的 junit 测试。

public static class MapWrapper {
    private String language;
    private Map<String, MyMapEntry> map;
}

public static class MyMapEntry {
    String name;
}

@Test
public void testParsing() {
    String json = "{\n" +
            "    \"root\": {\n" +
            "        \"language\": \"en\",\n" +
            "        \"map\": {\n" +
            "            \"k1\": {\n" +
            "                \"name\": \"n1\"\n" +
            "            },\n" +
            "            \"k2\": {\n" +
            "                \"name\": \"n2\"\n" +
            "            }\n" +
            "        }\n" +
            "    }\n" +
            "}";
    Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
    Type type = new TypeToken<Map<String, MapWrapper>>(){}.getType();
    Map<String, MapWrapper> parsed = gson.fromJson(json, type);
    MapWrapper mapWrapper = parsed.get("root");
    Assert.assertEquals("en", mapWrapper.language);
    Assert.assertEquals("n2", mapWrapper.map.get("k2").name);
}
于 2016-04-26T08:07:12.870 回答