2012-08-17 7 views
13

Làm thế nào tôi nên deserialize sau JSON để bỏ qua phần tử gốc và phân tích cú pháp phần bên trong của JSON này. Tôi muốn tránh tạo thêm, lớp thứ 3 Root, chỉ bao gồm trường MapWrapper.Bỏ qua phần tử gốc trong khi deserializing json

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

Vì vậy, tôi muốn chỉ có hai loại cổ phiếu này:

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

class MyMapEntry { 
    String name; 
} 

Trả lời

10

bạn có thể sử dụng GSON Thư viện cho việc này.

Mã dưới đây sẽ giải quyết được sự cố của bạn.

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

Giải pháp gọn gàng. +1 –

+1

mã này phân tích cú pháp json hai lần. Có thể tránh nó không? –

+0

có thể thực hiện điều đó bằng cách viết JsonDeserializer tùy chỉnh và đăng ký nó với GSON. – Byter

0

Bạn có thể deserialize nó thành một Map<String, MapWrapper>.

+0

How are you deserializing dữ liệu (hoặc kế hoạch)? (Bất kỳ khuôn khổ cụ thể nào?) –

2

Đây là mã tối ưu để làm điều đó trong một lần.

MapWrapper lớp

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 lớp

public class MyMapEntry { 

    String name; 

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

Custom deserializer

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); 
    } 
} 

đăng ký nó với GSON

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

Bây giờ deserialise với mã sau đây

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

điều này làm cho tôi tạo thêm lớp, đó là vấn đề từ việc bắt đầu. Làm như vậy, tốt hơn là tạo lớp 'Wraper' với một trường kiểu' MapWrapper' được gọi là root. –

+0

@Mathew Không cần lớp Wrapper nào thực sự là – Byter

+0

mà không có trình bao bọc, nó tạo ra đối tượng null, vì 'ctx.deserialize' sẽ gọi phương thức' MyDeserializer.deserialize' để tạo đối tượng 'MapWrapper' –

2

Hãy xem xét các JSON sau:

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

Các DTO cho JSON này mà không có phần tử gốc

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; 
    } 
} 

Chuyển đổi từ/đến JSON sử dụng các phương pháp sau (bạn có thể giữ điều này trong DTO hoặc một số lớp trợ giúp khác)

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

Giải pháp tốt giúp tôi – Riskhan

0

Lấy cảm hứng từ ý tưởng của Gustav Carlson Tôi quyết định mở rộng nó thành một mẫu cụ thể. Đây là bài kiểm tra junit để kiểm tra phân tích cú pháp JSON này dưới dạng Bản đồ.

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

Câu trả lời của tôi là muộn cho bên này.

Khi chúng tôi phân tích cú pháp Json, vùng chứa luôn là một lớp con JsonObject của JsonElement. Vì vậy, nếu chúng ta muốn bỏ qua nó, chúng ta chỉ cần đưa nó vào lớp con của nó và lấy trường giữ lớp bên trong của chúng ta.

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

Lưu ý: JsonObject và JSONObject là các lớp khác nhau (sử dụng nhập com.google.Json).

Bạn có thể khái quát hóa câu trả lời này để bạn không cần phải biết tên của lớp bên trong.Bạn sẽ làm điều này bằng cách đơn giản nhận được trường chỉ một và duy nhất của đối tượng vùng chứa. Tuy nhiên, tôi thấy không có cách nào để làm điều này ngoài việc khởi động trình lặp, không có phương thức getValue (atIndex) tôi có thể thấy, và tôi nghĩ bắt đầu một trình lặp có lẽ kém hiệu quả hơn là chỉ tìm kiếm trường theo tên (nhưng có thể sai rồi).

Phương pháp iterator trông giống như:

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