2016-11-15 25 views
8

EASY VERSIONChuyển đổi json để đối tượng Map.Entry với Gson

Nếu tôi hỏi Gson để chuyển đổi một số json hợp lệ để myMap nó không có vấn đề làm việc đó

public class MyMap{ 
    Map<Long,String> content; 
} 


MyMap myMap = gson.fromJson(json, new TypeToken<MyMap>() {}.getType()); 

VERSION HARD:

thế nào sao tôi có được Gson để làm như sau?

public class MyDS{ 
    Map<Map.Entry<Long,String>,Map<Long,String>> content; 
} 

MyDS myDS = gson.fromJson(json, new TypeToken<MyDS>() {}.getType()); 

Ví dụ json nếu bạn thực sự cần. hơn

"content": { 
     "[1, dog]": { 
     "1": "max", 
     "2": "pi", 
     "3": "robot", 
     "4": "catcher", 
     "5": "reaper" 
     }, 
     "[2, cat]": { 
     "6": "black", 
     "7": "white", 
     "8": "meow", 
     "9": "mice", 
     "10": "rat" 
     }, 
     "[3, rabbit]": { 
     "16": "bunny", 
     "17": "ears", 
     "28": "burgerbun", 
     "39": "alice", 
     "50": "tweak" 
     } 
    } 

ghi chú

Đối với biện pháp tốt, tôi cố gắng chạy một thử nghiệm đơn vị nơi mà tất cả tôi làm là cố gắng đọc các json với Gson, và tôi nhận được dấu vết lỗi sau:

at sun.misc.Unsafe.allocateInstance(Native method) 
java.lang.reflect.Method.invoke!(Native method) 
com.google.gson.internal.UnsafeAllocator$1.newInstance(UnsafeAllocator.java:48) 
com.google.gson.internal.ConstructorConstructor$14.construct(ConstructorConstructor.java:223) 
com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:207) 
com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40) 
com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:186) 
com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:145) 
com.google.gson.Gson.fromJson(Gson.java:861) 
com.google.gson.Gson.fromJson(Gson.java:826) 
com.google.gson.Gson.fromJson(Gson.java:775) 

Nó không quan trọng nếu các phím có dạng "[3, rabbit]" cho "{3, rabbit}"

+0

Bạn có thể trình bày mẫu json cho việc này không? – notionquest

+1

Sửa báo giá của bạn. – shmosel

+0

Các trích dẫn chỉ giống như vậy bởi vì tôi dán vào một textEditor. Nhưng họ ổn. Giống như tôi nói, nó hoạt động cho đến khi tôi cần một Entry cho khóa. –

Trả lời

4

Giả sử rằng bạn có một hợp lệJSON nội dung kiểu:

{ 
    "content": { 
     "[1, dog]": { 
     "1": "max", 
     "2": "pi", 
     "3": "robot", 
     "4": "catcher", 
     "5": "reaper" 
     }, 
     "[2, cat]": { 
     "6": "black", 
     "7": "white", 
     "8": "meow", 
     "9": "mice", 
     "10": "rat" 
     }, 
     "[3, rabbit]": { 
     "16": "bunny", 
     "17": "ears", 
     "28": "burgerbun", 
     "39": "alice", 
     "50": "tweak" 
     } 
    } 
} 

Để đạt được những gì bạn muốn, bạn chỉ có thể thực hiện của riêng Map.EntryDeserializer vì nó không thể được deserialized ra khỏi hộp vì nó là không phải mảng và {3, rabbit} không phải là đối tượng JSON hợp lệ.

Vì vậy Deserializer của bạn có thể dựa vào một biểu thức chính quy để trích xuất các chìa khóa và giá trị sau đó tạo ra một thể hiện của AbstractMap.SimpleEntry sử dụng các giá trị khai thác, một cái gì đó như:

public class MapEntryDeserializer implements JsonDeserializer<Map.Entry<Long, String>> { 

    /** 
    * Pattern corresponding to: 
    * Starts with [ 
    * <a non empty sequence of digit characters>, 
    * <a non empty sequence of any characters 
    * Ends with ] 
    */ 
    private static final Pattern PATTERN = Pattern.compile("^\\[(\\d+), ?(.+)\\]$"); 

    public Map.Entry<Long, String> deserialize(JsonElement json, Type typeOfT, 
     JsonDeserializationContext context) throws JsonParseException { 
     // Extract the key/value pair from Strings of type [3, rabbit] 
     String value = json.getAsString(); 
     Matcher matcher = PATTERN.matcher(value); 
     if (!matcher.find()) { 
      throw new JsonParseException(
       String.format("The map entry doesn't have the expected format: %s", value) 
      ); 
     } 
     return new AbstractMap.SimpleEntry<>(
      Long.valueOf(matcher.group(1)), matcher.group(2) 
     ); 
    } 
} 

Sau đó tôi có thể deserialize nội dung JSON của tôi với:

Type type = new TypeToken<MyDS>() {}.getType(); 
Gson gson = new GsonBuilder() 
    .registerTypeAdapter(Map.Entry.class, new MapEntryDeserializer()) 
    .create(); 

MyDS myDS = gson.fromJson(json, type); 
+0

Giải pháp tuyệt vời, tôi không 'có được nhóm thứ hai của regex' ([^]] +) 'bạn có thể giải thích nó không? – AxelH

+2

@AxelH nó có nghĩa là một chuỗi ký tự bất kỳ trừ ']' –

+0

Tôi nghĩ chúng ta gần như ở đó. Nhưng tôi tiếp tục nhận được lỗi sau: '" Mục nhập bản đồ không có định dạng mong muốn: 1 = dog' –

1

Theo thứ tài liệu điện tử cho Map.Entry:

The only way to obtain a reference to a map entry is from the iterator of this collection-view.

https://docs.oracle.com/javase/8/docs/api/java/util/Map.Entry.html

Điều này có nghĩa bạn không thể có được Map.Entry cho đến khi bạn đã tạo bản đồ ban đầu. Để đạt được những gì bạn muốn, bạn sẽ cần phải phân tích cú pháp JSON thành Bản đồ, sau đó lặp lại nó để chèn nó vào đối tượng MyDS của bạn.

Có nói rằng, tùy thuộc vào mục đích sử dụng cuối cùng của bạn, có thể có cách tổ chức lại/khóa dữ liệu tốt hơn sau khi phân tích cú pháp.

+0

Tài liệu này đề cập đến việc sử dụng thông thường cho các mục nhập trong bản đồ, nhưng không có gì thực sự ngăn bạn tạo một thể hiện của 'Map.Entry' và thậm chí có cả các triển khai tiện ích như' AbstractMap.SimpleEntry' và 'AbstractMap.SimpleImmutableEntry' . – shmosel

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