Java 反序列化json时跳过根元素

Java 反序列化json时跳过根元素,java,json,gson,Java,Json,Gson,我应该如何反序列化下面的JSON以跳过根元素并只解析JSON的内部部分。我希望避免创建额外的第三类根,它只包括MapWrapper字段 { "root": { "language": "en", "map": { "k1": { "name": "n1", }, "k2": { "name": "n2",

我应该如何反序列化下面的JSON以跳过根元素并只解析JSON的内部部分。我希望避免创建额外的第三类
,它只包括
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;
}
类映射包装器{
私有字符串语言;
私人地图;
}
类MyMapEntry{
字符串名;
}

您可以将其反序列化为
映射
您可以为此使用
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);
公共类convertJsonObject{
私有静态Gson Gson=new GsonBuilder().create();
公共静态final T getFromJSON(字符串json,类clazz){
返回gson.fromJson(json,clazz);
}
公共静态最终字符串toJSON(T clazz){
返回gson.toJson(clazz);
}
}
字符串json;//你的jsonString
Map r=ConvertJsonToObject.getFromJSON(json,Map.class);
字符串innerJson=ConvertJsonToObject.toJson(r.get(“root”);
MapWrapper\u r=ConvertJsonToObject.getFromJSON(innerJson,MapWrapper.class);

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

MapWrapper
class

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;
    }
}
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);
    }   
}
现在使用以下代码反序列化

String json; // your jsonString
MapWrapper result = ConvertJsonToObject.getFromJSON(json,MapWrapper.class);

考虑以下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或其他帮助类中)


受到古斯塔夫·卡尔森想法的启发,我决定将其扩展到一个具体的例子。这里有一个junit测试,测试如何将这个JSON解析为映射

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);
}
公共静态类映射包装器{
私有字符串语言;
私人地图;
}
公共静态类MyMapEntry{
字符串名;
}
@试验
公共void testParsing(){
字符串json=“{\n”+
“\”根\“:{\n”+
“\'language\:\'en\,\n”+
“\”映射\“:{\n”+
“\“k1\”:{\n”+
“\”名称\“:\”n1\“\n”+
},\n+
“\“k2\”:{\n”+
“\”名称\“:\”n2\“\n”+
“}\n”+
“}\n”+
“}\n”+
"}";
Gson Gson=new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_,带下划线)。create();
Type Type=new-TypeToken(){}.getType();
Map parsed=gson.fromJson(json,类型);
MapWrapper=parsed.get(“根”);
Assert.assertEquals(“en”,mapWrapper.language);
Assert.assertEquals(“n2”,mapWrapper.map.get(“k2”).name);
}

我的回答迟到了

解析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();

您如何对数据进行反序列化(或计划进行反序列化)?(任何特定的框架?)是的,可以通过编写自定义JsonDeserializer并将其注册到GSON来实现。任何示例都值得欣赏。这使我创建了额外的类,这是beggining的问题。这样做,最好创建一个名为root的
MapWrapper
类型字段的
Wrapper
类。@Mathew根本不需要Wrapper类,实际上,如果没有Wrapper,它会创建空对象,原因
ctx.deserialize
将调用
MyDeserializer.deserialize
方法来创建
MapWrapper
对象毕竟,我认为在这种特殊情况下,为根元素创建额外的包装类是最干净的解决方案。内部结构可以隐藏在数据提供程序类中,因此代码质量没有任何问题(非常简单的数据保持器类,具有非常指定的函数)。感谢您的努力-我接受您的另一个解决方案,因为它是最短的,而且处理开销很小-最好的选择。好的解决方案对我来说是正确的
    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);
    JsonElement jsonQuery = ((JsonObject) jsonContainer).entrySet().iterator()
                            .next().getValue();