2012-08-17 80 views
13

如何反序列化以下JSON以跳過根元素並僅解析此JSON的內部部分。我想避免創建額外的第三類Root,其中只包括MapWrapper字段。在反序列化json時跳過根元素

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

所以我想只有這兩個類:

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

class MyMapEntry { 
    String name; 
} 

回答

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); 
+0

整潔的解決方案。 +1 – 2012-08-17 11:18:02

+1

此代碼解析json兩次。是否有可能避免它? – 2012-08-17 11:28:47

+0

是的,可以通過編寫自定義的JsonDeserializer並將其註冊到GSON來完成。 – Byter 2012-08-17 11:30:04

0

你可以反序列化到一個Map<String, MapWrapper>

+0

你是如何反序列化數據(或計劃)? (任何特定的框架?) – 2012-08-17 11:14:29

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() 
註冊它

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

的DTO此JSON而不根元素從/

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的給:

現在用下面的代碼

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

這使得我創建額外的類,這是從開始的問題。這樣做更好地創建'Wraper'類,其中一個類型爲MapWrapper的字段稱爲root。 – 2012-08-17 11:59:19

+0

@Mathew不需要包裝類實際上 – Byter 2012-08-17 12:02:08

+0

沒有包裝它創建空對象,因爲'ctx.deserialize'會調用'MyDeserializer.deserialize'方法來創建'MapWrapper'對象 – 2012-08-17 12:06:44

2

考慮以下JSON deserialise以下方法(您可以將其保留在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; 
} 
+0

對我有好的解決方案 – Riskhan 2018-02-22 06:04:37

0

受Gustav Carlson想法的啓發,我決定將它擴展到一個具體的樣本。這是一個junit測試,測試將這個JSON解析爲Map。

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); 
} 
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)方法,我可以看到,我認爲開始迭代器可能不如僅按名稱查找字段(但可以是錯誤)。

iterator方法是這樣的:

JsonElement jsonQuery = ((JsonObject) jsonContainer).entrySet().iterator() 
          .next().getValue();