2013-04-21 31 views
6

Tôi muốn làm cho gson có thể trả về đối tượng EnumMap. Tôi sử dụng đoạn mã sauGSON từJson trả về LinkedHashMap thay vì EnumMap

package sandbox; 

import com.google.gson.Gson; 
import com.google.gson.reflect.TypeToken; 
import java.util.EnumMap; 
import java.util.Map; 

/** 
* 
* @author yccheok 
*/ 
public class Sandbox { 

    public static void main(String[] args) throws InterruptedException {  
     testGson(); 
    } 

    public static enum Country { 
     Malaysia, 
     UnitedStates 
    } 

    public static void testGson() { 
     Map<Country, String> enumMap = new EnumMap<Country, String>(Country.class); 
     enumMap.put(Country.Malaysia, "RM"); 
     enumMap.put(Country.UnitedStates, "USD"); 
     Gson gson = new Gson(); 
     String string = gson.toJson(enumMap); 
     System.out.println("toJSon : " + string); 
     enumMap = gson.fromJson(string, new TypeToken<EnumMap<Country, String>>(){}.getType()); 
     System.out.println("fromJSon : " + enumMap); 
     System.out.println("fromJSon : " + enumMap.getClass()); 
    } 
} 

Tuy nhiên, tôi nhận được sau

toJSon : {"Malaysia":"RM","UnitedStates":"USD"} 
fromJSon : {Malaysia=RM, UnitedStates=USD} 
fromJSon : class java.util.LinkedHashMap 

mặc dù tôi đã sử dụng new TypeToken<EnumMap<Country, String>>(){}.getType() để cụ thể tôi muốn EnumMap thay vì LinkedHashMap

Làm thế nào tôi có thể làm gson để trả lại EnumMap?

Trả lời

9

Ngay cả với mã thông báo loại, Gson chỉ có thể deserialize dữ liệu vào các lớp có hàm tạo mặc định. Và EnumMap không có (nó cần được khởi tạo với kiểu enum mà các phần tử của nó sẽ khớp). Cách đơn giản nhất xung quanh vấn đề này là để xác định và sử dụng một InstanceCreator:

Giao diện này được thực hiện để tạo ra các trường hợp của một lớp học mà không định nghĩa một constructor không có args. Nếu bạn có thể sửa đổi lớp, thay vào đó bạn nên thêm một hàm tạo riêng hoặc không có công khai. Tuy nhiên, điều đó là không thể đối với các lớp thư viện, chẳng hạn như các lớp JDK hoặc thư viện của bên thứ ba mà bạn không có mã nguồn. Trong những trường hợp như vậy, bạn nên định nghĩa một trình tạo cá thể cho lớp đó. Việc triển khai giao diện này nên được đăng ký với phương thức GsonBuilder.registerTypeAdapter (Type, Object) trước khi Gson có thể sử dụng chúng.

Heres một số mã ví dụ:

InstanceCreator:

class EnumMapInstanceCreator<K extends Enum<K>, V> implements 
     InstanceCreator<EnumMap<K, V>> { 
    private final Class<K> enumClazz; 

    public EnumMapInstanceCreator(final Class<K> enumClazz) { 
     super(); 
     this.enumClazz = enumClazz; 
    } 

    @Override 
    public EnumMap<K, V> createInstance(final Type type) { 
     return new EnumMap<K, V>(enumClazz); 
    } 
} 

mã kiểm tra:

final Gson gson = new GsonBuilder().registerTypeAdapter(
     new TypeToken<EnumMap<Country, String>>() { 
     }.getType(), 
     new EnumMapInstanceCreator<Country, String>(Country.class)) 
     .create(); 

final Map<Country, String> enumMap = new EnumMap<Country, String>(
     Country.class); 
enumMap.put(Country.Malaysia, "RM"); 
enumMap.put(Country.UnitedStates, "USD"); 
String string = gson.toJson(enumMap); 
System.out.println("toJSon : " + string); 

final Map<Country, String> reverseEnumMap = gson.fromJson(string, 
     new TypeToken<EnumMap<Country, String>>() { 
     }.getType()); 
System.out.println("fromJSon (Class): " + reverseEnumMap.getClass()); 
System.out.println("fromJSon : " + reverseEnumMap); 
+0

là kinda lạ, tôi sử dụng mã của bạn một cách chính xác, nhưng tôi nhận được LinkedHashMap vẫn ở cạnh tôi. Tôi đang sử dụng gson-2.1. Nó có quan trọng không? –

+3

Xin lỗi. Sử dụng gson 2.2.3 mới nhất hoạt động hoàn hảo. –

+1

@CheokYanCheng Sử dụng GSON 2.2.3 nó có hoạt động cho bạn ra khỏi hộp mà không có bất kỳ thay đổi mã nào không? –

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