2015-01-25 33 views
6

Tôi đang cố gắng deserialize một mảng JSON bằng cách sử dụng GSON. Tất cả các đối tượng lồng nhau của tôi được nhúng bên trong một đối tượng "được nhúng".GSON: Xóa đối tượng cha mẹ không cần thiết trong khi deserializing

{ 
    "Book": { 
     "name": "Book 1", 
     "published": 1999, 
     "links": { 
      "url": "www.book1.com" 
     }, 
     "embedded": { 
      "Author": { 
       "name": "John Doe", 
       "links": { 
        "url": "www.johndoe.com" 
       } 
      } 
     } 
    } 
} 

tôi cũng có thể có một tình huống như thế này:

{ 
    "Book": { 
     "name": "Book 1", 
     "published": 1999, 
     "links": { 
      "url": "www.book1.com" 
     }, 
     "embedded": { 
      "Publisher": { 
       "name": "Publishing Company", 
       "links": { 
        "url": "www.publishingcompany.com" 
       } 
      } 
     } 
    } 
} 

Đây là một ví dụ cực kỳ đơn giản. Một số đối tượng của tôi có thể được lồng sâu 2 hoặc 3 cấp độ sâu và tất cả đều nằm trong đối tượng "được nhúng". Ngoài ra, mỗi đối tượng có một "url" lồng nhau bên trong một đối tượng "liên kết". Tôi có khoảng 20 đối tượng mô hình khác nhau, mỗi đối tượng có nhiều trường và mọi người trong số chúng đều có đối tượng "được nhúng". Tôi bắt đầu viết deserializers tùy chỉnh cho mỗi mô hình, nhưng điều đó dường như bỏ lỡ toàn bộ điểm sử dụng gson, và tôi có thể không phải lúc nào cũng biết đối tượng được nhúng là gì.

Tôi tìm thấy điều này answer, nhưng nó là để sắp xếp các đối tượng. Tôi đã cố gắng để tìm ra điều này trong một thời gian và không tìm thấy bất cứ điều gì hoạt động.

mô hình

My Book trông như thế này:

public class Book { 
    String name; 
    int published; 
    String url; 
    Author author; 
    Publisher publisher; 
} 

Author lớp:

public class Author { 
    String name; 
    String url; 
} 

lớp Publisher:

public class Publisher { 
    String name; 
    String url; 
} 

Và đây là Sách của tôi deserializer cho đến nay:

public class BookDeserializer implements JsonDeserializer<Book> { 
    @Override 
    public Book deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 

     final JsonObject jsonObject = json.getAsJsonObject(); 

     Book book = new Book(); 
     book.setName(jsonObject.get("name").getAsString()); 
     book.setPublished(jsonObject.get("published").getAsInt()); 
     String url = jsonObject.getAsJsonObject("links").get("url").getAsString(); 
     book.setUrl(url); 

     // 1) How to get rid of this and skip to the "real" nested object? 
     final JsonObject embeddedObject = jsonObject.getAsJsonObject("embedded"); 

     // 2) See what the "embedded" object actually is. 
     String embeddedModel; 
     Set<Map.Entry<String, JsonElement>> entrySet = embeddedObject.entrySet(); 
     for (Map.Entry<String, JsonElement> entry : entrySet) { 

      // Author or Publisher 
      embeddedModel = entry.getKey(); 
     } 

     // We have the model's key, now add code here to deserialize whatever the object is 

     return book; 
    } 
} 

Tôi vẫn phải phân tích cú pháp và cài đặt từng trường cho Sách. Sau đó, tôi sẽ phải thêm mã để xác định và sử dụng deserializer chính xác cho đối tượng lồng nhau. Hình như tôi vẫn sẽ cần một deserializer tùy chỉnh cho từng đối tượng để có được "url". Tôi khá mới để gson, vì vậy có lẽ chỉ có một cái gì đó mà tôi nhìn, nhưng có vẻ như tôi cũng có thể chỉ cần phân tích cú pháp tất cả các json và thậm chí không sử dụng gson. Có lẽ có một cách để làm phẳng ra json?

Bất kỳ ý tưởng nào về cách phân tích cú pháp này và vẫn sử dụng sự tiện lợi của gson, hoặc điều này thậm chí có thể? Có lẽ Jackson có thể xử lý tốt hơn?

+0

Cant gson deserialize và tuần tự hóa tùy chọn này theo mặc định? Tại sao bạn cần phải viết của riêng bạn? – user489041

Trả lời

1

Tạo một lớp được gọi là nhúng và thêm nó như là một lĩnh vực trong Sách:

public class Book { 
    String name; 
    int published; 
    Embedded embedded; 
} 

Sau đó tạo một lớp nhúng:

public class Embedded { 
    Author Author; 
    Publisher Publisher; 
} 

Chỉ cần mô hình lớp học của bạn sau khi JSON của bạn

+0

Đây là cách tôi nghĩ ban đầu để làm điều này, nhưng hy vọng có một giải pháp "thanh lịch" hơn. Nó có vẻ như một sự lãng phí để tạo ra một lớp Liên kết và nhúng (sẽ có nhiều hơn thế này), mỗi đối tượng có thể thậm chí tôi không sử dụng. Tôi đoán nó là dễ dàng hơn so với việc tạo ra deserializers tùy chỉnh cho mỗi mặc dù. – Mark

+0

chúng tôi sử dụng [Dozer] (http://dozer.sourceforge.net/) trong công ty của chúng tôi để lập bản đồ giữa các lớp học này. trên thực tế, chúng tôi tạo ra một đối tượng phẳng phản hồi mà chúng tôi muốn gửi và sử dụng dozer để ánh xạ chúng. nó giúp tự động lập bản đồ các hạt với nhau – alizelzele

1

My suy nghĩ đầu tiên là phân tích cú pháp JSON và hack nó xung quanh nhưng có vẻ như GSON JsonObject là không thay đổi.

Do đó, tôi sẽ viết một trình phân tích luồng đơn giản, tìm kiếm "embedded": {"links": { và xóa chúng. Chạy một bộ đếm khung đơn giản để loại bỏ giá đỡ phù hợp. Nếu thời gian cho phép tôi có thể ném một với nhau.

BTW - Mẫu JSON của bạn thiếu dấu phẩy - dán here để kiểm tra.

Đã thêm: - Trình phân tích cú pháp luồng không nằm trong tầm tay - mặc dù nó sẽ là tùy chọn gọn gàng hơn. Nếu bạn có thể tìm thấy trình phân tích cú pháp luồng JSON như SAX cho XML, bạn có thể làm tốt hơn theo cách đó.

Cơ chế thứ hai giả sử bạn có thể phù hợp với toàn bộ JSON của bạn trong một Chuỗi trong bộ nhớ. Không lý tưởng nhưng có lẽ là một giải pháp chấp nhận được đối với hầu hết các thiết lập. Điều này sau đó sử dụng một regex đơn giản cộng với một truy cập khung để loại bỏ các bộ phận cần thiết.

/** 
* Finds the first matching close brace - assuming an open brace has just been removed from the `start` position. 
*/ 
private int closeBrace(StringBuilder s, int start) { 
    int count = 1; 
    boolean inQuotes = false; 
    for (int i = start; i < s.length(); i++) { 
     char ch = s.charAt(i); 
     // Special case escapes. 
     if (ch != '\\') { 
      switch (ch) { 
       case '"': 
        inQuotes = !inQuotes; 
        break; 
       case '{': 
        if (!inQuotes) { 
         count += 1; 
        } 
        break; 
       case '}': 
        if (!inQuotes) { 
         count -= 1; 
         if (count == 0) { 
          return i; 
         } 
        } 
        break; 
      } 
     } else { 
      // Escape character - skip the next character. 
      if (i < s.length()) { 
       i += 1; 
      } 
     } 
    } 
    // Failed to find 
    return s.length(); 
} 

/** 
* Removes the JSON specified. 
*/ 
private String hack(String json, String remove) { 
    // Transfer to an sb for slicing and dicing. 
    StringBuilder s = new StringBuilder(json); 
    // Build my pattern 
    Pattern p = Pattern.compile("\"" + remove + "\"\\s*:\\s*\\{"); 
    // Make my Matchjer. 
    Matcher m = p.matcher(s); 
    // Is it there? 
    while (m.find()) { 
     int start = m.start(); 
     int end = m.end(); 
     // Kill the match. 
     s.delete(start, end); 
     // Walk forward to find the close brace. 
     end = closeBrace(s, start); 
     // And remove it. 
     if (end < s.length()) { 
      s.delete(end, end + 1); 
     } 
     // Rebuild the matcher. 
     m = p.matcher(s); 
    } 
    return s.toString(); 
} 

private void test(String json) { 
    JsonParser parser = new JsonParser(); 
    JsonElement e = parser.parse(json); 
    System.out.println(e); 
} 

public void test() { 
    String json = "{'Book': {'name': 'Book \\'1\\'','published': 1999,'links': {'url': 'www.book1.com'},'embedded': {'Publisher': {'name': 'Publishing Company','links': {'url': 'www.publishingcompany.com'}}}}}".replace("'", "\""); 
    test(json); 
    json = hack(json, "embedded"); 
    test(json); 
    json = hack(json, "links"); 
    test(json); 
} 

in:

{"Book":{"name":"Book \"1\"","published":1999,"links":{"url":"www.book1.com"},"embedded":{"Publisher":{"name":"Publishing Company","links":{"url":"www.publishingcompany.com"}}}}} 
{"Book":{"name":"Book \"1\"","published":1999,"links":{"url":"www.book1.com"},"Publisher":{"name":"Publishing Company","links":{"url":"www.publishingcompany.com"}}}} 
{"Book":{"name":"Book \"1\"","published":1999,"url":"www.book1.com","Publisher":{"name":"Publishing Company","url":"www.publishingcompany.com"}}} 

mà trông hơi giống như những gì bạn đang tìm kiếm.

+0

Cảm ơn sự giúp đỡ và tôi đã sửa lỗi JSON. Điều này nghe có vẻ như một ý tưởng tốt và một số mã mẫu sẽ là tuyệt vời! Gson có hỗ trợ phát trực tuyến không, đó là những gì bạn đang đề cập đến? – Mark

+0

@Mark - See ** Added ** - Không phải là một giải pháp rất đẹp nhưng nó sẽ làm việc cho các đối tượng JSON vừa và nhỏ. – OldCurmudgeon

+0

Cảm ơn bạn đã cung cấp ví dụ về mã. Tuy nhiên, tôi sẽ đi với chỉ cần tạo ra các lớp học thêm để mô hình java của tôi phù hợp với json. Có vẻ như gson có thể không cung cấp một cách tích hợp để unwrap các đối tượng lồng nhau đã chọn. – Mark

Các vấn đề liên quan