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);
source share