2010-12-28 31 views
11

Tôi muốn tuần tự hóa lớp Ví dụ bên dưới thành JSON bằng GSON.Làm thế nào để tuần tự hóa Bản đồ Bản đồ với GSON?

import com.google.gson.Gson; 
import com.google.gson.GsonBuilder; 
import java.util.LinkedHashMap; 

public class Example 
{ 
    private LinkedHashMap<String,Object> General; 

    private static final String VERSION="Version"; 
    private static final String RANGE="Range"; 
    private static final String START_TIME="Start_Time"; 
    private static final String END_TIME="End_Time"; 

    public Example() { 
     General = new LinkedHashMap<String,Object>(); 
     General.put(VERSION, "0.1"); 

     LinkedHashMap<String,String> Range = new LinkedHashMap<String, String>(); 
     Range.put(START_TIME, "now"); 
     Range.put(END_TIME, "never"); 

     General.put(RANGE, Range); 
    } 

    public String toJSON() { 
     Gson gson = new GsonBuilder().serializeNulls().create(); 
     return gson.toJson(this); 
    } 
} 

tôi mong đợi để có được kết quả như sau:

{"General":{"Version":"0.1","Range":{"Start_Time":"now","End_Time":"never"}}} 

Nhưng gọi hàm toJSON() lợi nhuận

{"General":{"Version":"0.1","Range":{}}} 

Dường như GSON không thể serialize Bản đồ Range bên trong Map General. Đây có phải là một hạn chế của GSON hay tôi đang làm điều gì sai ở đây?

+2

Nếu câu trả lời khác là Trình nối tiếp bản đồ mặc định và chính xác sẽ không xử lý các bản đồ lồng nhau, tôi sẽ gửi một báo cáo lỗi cho nhóm GSON. Nó có vẻ như thực sự xấu mặc định với tôi; ít nhất nó phải ném một ngoại lệ thay vì lặng lẽ nuốt nội dung. – StaxMan

+0

+1 @StaxMan có vẻ như vậy. Tôi đã thấy điều này trước đó, đã đưa ra một số công việc xung quanh. Nếu có một số cách để làm điều này, nó có giá trị tài liệu. – Nishant

Trả lời

8

Lý do tại sao Nishant's answer công trình là vì constructor mặc định Gson của phép tất cả các loại công cụ mỗi mặc định mà bạn nếu không sẽ phải tự enably sử dụng GsonBuilder.

Từ JavaDocs:

xây dựng một đối tượng Gson với cấu hình mặc định. Cấu hình mặc định có các cài đặt sau:

  • JSON được tạo bởi phương thức toJson được trình bày gọn gàng. Điều này có nghĩa là tất cả các không gian trắng không cần thiết được loại bỏ. Bạn có thể thay đổi hành vi này bằng GsonBuilder.setPrettyPrinting().
  • JSON được tạo sẽ bỏ qua tất cả các trường rỗng. Lưu ý rằng null trong mảng được giữ như là kể từ khi một mảng là một danh sách theo thứ tự. Hơn nữa, nếu một trường không phải là null, nhưng JSON của nó được tạo ra trống, trường này được giữ lại. Bạn có thể cấu hình Gson để tuần tự hóa các giá trị null bằng cách thiết lập GsonBuilder.serializeNulls().
  • Gson cung cấp tuần tự hóa mặc định và deserialization cho Enums, Bản đồ, java.net.URL, java.net.URI, java.util.Locale, java.util.Date, java.math.BigDecimal và java.math.BigInteger các lớp học. Nếu bạn muốn thay đổi biểu diễn mặc định, bạn có thể làm như vậy bằng cách đăng ký một bộ điều hợp kiểu thông qua GsonBuilder.registerTypeAdapter (Type, Object).
  • Định dạng ngày mặc định giống như java.text.DateFormat.DEFAULT. Định dạng này bỏ qua phần mili giây của ngày trong quá trình tuần tự hóa. Bạn có thể thay đổi điều này bằng cách gọi GsonBuilder.setDateFormat (int) hoặc GsonBuilder.setDateFormat (String).
  • Theo mặc định, Gson bỏ qua chú thích com.google.gson.annotations.Expose. Bạn có thể kích hoạt Gson để tuần tự hóa/deserialize chỉ những trường được đánh dấu bằng chú thích này thông qua GsonBuilder.excludeFieldsWithoutExposeAnnotation().
  • Theo mặc định, Gson bỏ qua com.google.gson.annotations.Kể từ khi chú thích. Bạn có thể cho phép Gson sử dụng chú thích này thông qua GsonBuilder.setVersion (double).
  • Chính sách đặt tên trường mặc định cho Json đầu ra giống như trong Java. Vì vậy, một lớp Java versionNumber sẽ được xuất dưới dạng "versionNumber @ quot; trong Json. Các quy tắc tương tự được áp dụng cho ánh xạ Json đến các lớp Java. Bạn có thể thay đổi chính sách này thông qua GsonBuilder.setFieldNamingPolicy (FieldNamingPolicy). mặc định, Gson không bao gồm các lĩnh vực thoáng qua hoặc tĩnh từ xem xét cho serialization và deserialization. Bạn có thể thay đổi hành vi này qua GsonBuilder.excludeFieldsWithModifiers (int).

OK, bây giờ tôi thấy vấn đề là gì. các Trình nối tiếp bản đồ mặc định, như bạn mong đợi, không hỗ trợ bản đồ lồng nhau. Như bạn có thể thấy trong this source snippet from DefaultTypeAdapters (đặc biệt là nếu bạn bước qua một trình gỡ lỗi), biến số childGenericType được đặt thành loại java.lang.Object vì một số lý do bí ẩn, do đó loại thời gian chạy của giá trị không bao giờ được phân tích.

Hai giải pháp, tôi đoán:

  1. Implement your own Map serializer/deserializer
  2. Sử dụng một phiên bản phức tạp hơn của phương pháp của bạn, một cái gì đó như thế này:

    public String toJSON(){ 
        final Gson gson = new Gson(); 
        final JsonElement jsonTree = gson.toJsonTree(General, Map.class); 
        final JsonObject jsonObject = new JsonObject(); 
        jsonObject.add("General", jsonTree); 
        return jsonObject.toString(); 
    } 
    
+0

Xin lỗi, bình luận đầu tiên của tôi về câu trả lời của Nishant là sai. Đề xuất của anh ta không hoàn toàn phù hợp với tôi. – asmaier

+0

@asmaier ok, thêm một số nội dung hơn vào câu trả lời của tôi –

+0

một cách kỳ lạ, nếu bạn thay thế LinkedHashMap bằng ImmutableMap thì công việc có ổn không. – Nishant

4

Hãy thử điều này:

Gson gson = new Gson(); 
System.out.println(gson.toJson(General)); 

Không chắc chắn nếu bạn vẫn đang tìm kiếm một giải pháp, công trình này cho tôi:

import java.util.LinkedHashMap; 

import com.google.common.collect.ImmutableMap; 
import com.google.gson.Gson; 
import com.google.gson.GsonBuilder; 

public class Example { 
// private static LinkedHashMap<String,Object> General; 
    private ImmutableMap General; 

    private static final String VERSION="Version"; 
    private static final String RANGE="Range"; 
    private static final String START_TIME="Start_Time"; 
    private static final String END_TIME="End_Time"; 

    public Example() { 

     LinkedHashMap<String,String> Range = new LinkedHashMap<String, String>(); 
     Range.put(START_TIME, "now"); 
     Range.put(END_TIME, "never"); 

//  General.put(RANGE, Range); 
     General = ImmutableMap.of(VERSION, "0.1", RANGE, Range); 
    } 

    public String toJSON() { 
//  Gson gson = new GsonBuilder().serializeNulls().create(); 
      Gson gson = new Gson(); 
      return gson.toJson(this); 
    } 

} 

lợi nhuận: { "General": {" Phiên bản ":" 0,1 "," Phạm vi ": {" Start_Time ":" bây giờ "," End_Time ":" never "}}}


Rõ ràng, bạn có thể sử dụng ImmutableMap.copyOf(your_hashmap)here thay

+1

Nó hoạt động, nhưng tại sao? Ngoài ra nó là một chút bất tiện. Nếu tôi muốn thêm nhiều bản đồ vào lớp của tôi Ví dụ, tôi phải viết hàm toJSON() của tôi như sau: String out = gson.toJson (this.General); out + = gson.toJson (this.Map2); out + = gson.toJson (this.map3); ... trả lại, ' – asmaier

+0

không chắc chắn bạn thân. Tôi đã có vấn đề này, tôi đã đi xuống con đường này. Tôi cho rằng nguyên nhân là http://sites.google.com/site/gson/gson-user-guide#TOC-Nested-Classes-including-Inner-Clas – Nishant

+0

Xin lỗi, nhận xét đầu tiên của tôi sai và tôi không thể chỉnh sửa nó nữa. Sử dụng 'gson.toJson (General)' trả về '{" Phiên bản ":" 0,1 "," Phạm vi ": {" Start_Time ":" bla "," End_Time ":" blu "}," Checksum ":" + 1 " } '. Nhưng tôi muốn có '{" General ": {" Version ":" 0.1 ", ....'. vì vậy giải pháp của bạn không hoạt động hoàn toàn cho tôi. – asmaier

1

Một lựa chọn đơn giản hơn sẽ được sử dụng Jackson thay vì GSON, việc tuần tự hóa bản đồ lồng nhau hoạt động ra khỏi hộp:

LinkedHashMap<String, Object> general; 
    general = new LinkedHashMap<String, Object>(); 
    general.put("Version", "0.1"); 

    LinkedHashMap<String, String> Range = new LinkedHashMap<String, String>(); 
    Range.put("Start_Time", "now"); 
    Range.put("End_Time", "never"); 

    general.put("Range", Range); 

    // Serialize the map to json using Jackson 
    ByteArrayOutputStream os = new ByteArrayOutputStream(); 
    new org.codehaus.jackson.map.ObjectMapper().writer().writeValue(os, 
      general);  
    String json = os.toString(); 
    os.close(); 

    System.out.println(json); 

Output:

{ "Version": "0.1", "Phạm vi": { "START_TIME": "bây giờ", "END_TIME": "không bao giờ"}}

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