GSON fromJson returns LinkedHashMap instead of EnumMap

I want gson to be able to return an EnumMap object. I am using the following code

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

However, I get the following

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

although I used new TypeToken<EnumMap<Country, String>>(){}.getType() for the specific I want EnumMap instead of LinkedHashMap

How to force gson to return EnumMap ?

+6
source share
1 answer

Even with a type marker, Gson can only deserialize data into classes that have a default constructor. And EnumMap does not have one (it needs to create an instance with an enumeration type that will correspond to its elements). The easiest way to solve this problem is to define and use InstanceCreator :

This interface is implemented to instantiate a class that the no-args constructor does not define. If you can change the class, you should instead add a private or public no-args constructor. However, this is not possible for library classes such as JDK classes, or a third-party library in which you do not have source code. In such cases, you must define the instance creator for the class. Implementations of this interface must be registered using the GsonBuilder.registerTypeAdapter (Type, Object) method before Gson can use them.

Here is a sample code:

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

Test code:

 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); 
+9
source

All Articles