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