2013-04-21 2 views
6

Desidero rendere Gson in grado di restituire un oggetto EnumMap. Io uso il seguente codiceGSON daJson restituisce LinkedHashMap invece di 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()); 
    } 
} 

Comunque, sto ottenendo il seguente

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

anche se avevo utilizzato new TypeToken<EnumMap<Country, String>>(){}.getType() a speciali Io voglio EnumMap invece di LinkedHashMap

Come posso fare gson restituire EnumMap?

risposta

9

Anche con un token di tipo, Gson può solo deserializzare i dati in classi che hanno un costruttore predefinito. E EnumMap non ne ha uno (deve essere istanziato con il tipo di enumerazione che i suoi elementi corrisponderanno). Il modo più semplice a questo problema è quello di definire e utilizzare un InstanceCreator:

Questa interfaccia è implementata per creare istanze di una classe che non definisce un costruttore senza argomenti. Se è possibile modificare la classe, è necessario aggiungere un costruttore privato o no-args pubblico. Tuttavia, ciò non è possibile per le classi di libreria, come le classi JDK o una libreria di terze parti di cui non si dispone di codice sorgente. In questi casi, dovresti definire un creatore di istanza per la classe. Le implementazioni di questa interfaccia devono essere registrate con il metodo GsonBuilder.registerTypeAdapter (Type, Object) prima che Gson sia in grado di usarle.

Ecco qualche esempio di codice:

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

Codice di prova:

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

È un po 'strano, io uso il codice esattamente, ma mi sto ancora LinkedHashMap al mio fianco. Sto usando gson-2.1. Importa? –

+3

Siamo spiacenti. Usare l'ultima versione 2.2.3 di gson funziona perfettamente. –

+1

@CheokYanCheng L'utilizzo di GSON 2.2.3 funziona immediatamente senza alcun cambiamento di codice? –