Support EnumMap deserialization (#2071)

This commit is contained in:
Marcono1234 2022-02-04 16:20:32 +01:00 committed by GitHub
parent e2e851c9bc
commit 565b7a198e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 38 additions and 1 deletions

View File

@ -23,6 +23,7 @@ import java.lang.reflect.Type;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.EnumMap;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
@ -199,7 +200,26 @@ public final class ConstructorConstructor {
} }
if (Map.class.isAssignableFrom(rawType)) { if (Map.class.isAssignableFrom(rawType)) {
if (ConcurrentNavigableMap.class.isAssignableFrom(rawType)) { // Only support creation of EnumMap, but not of custom subtypes; for them type parameters
// and constructor parameter might have completely different meaning
if (rawType == EnumMap.class) {
return new ObjectConstructor<T>() {
@Override public T construct() {
if (type instanceof ParameterizedType) {
Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0];
if (elementType instanceof Class) {
@SuppressWarnings("rawtypes")
T map = (T) new EnumMap((Class) elementType);
return map;
} else {
throw new JsonIOException("Invalid EnumMap type: " + type.toString());
}
} else {
throw new JsonIOException("Invalid EnumMap type: " + type.toString());
}
}
};
} else if (ConcurrentNavigableMap.class.isAssignableFrom(rawType)) {
return new ObjectConstructor<T>() { return new ObjectConstructor<T>() {
@Override public T construct() { @Override public T construct() {
return (T) new ConcurrentSkipListMap<Object, Object>(); return (T) new ConcurrentSkipListMap<Object, Object>();

View File

@ -31,7 +31,10 @@ import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.EnumMap;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Map;
import java.util.Set; import java.util.Set;
import junit.framework.TestCase; import junit.framework.TestCase;
/** /**
@ -150,6 +153,8 @@ public class EnumTest extends TestCase {
public void testEnumSet() { public void testEnumSet() {
EnumSet<Roshambo> foo = EnumSet.of(Roshambo.ROCK, Roshambo.PAPER); EnumSet<Roshambo> foo = EnumSet.of(Roshambo.ROCK, Roshambo.PAPER);
String json = gson.toJson(foo); String json = gson.toJson(foo);
assertEquals("[\"ROCK\",\"PAPER\"]", json);
Type type = new TypeToken<EnumSet<Roshambo>>() {}.getType(); Type type = new TypeToken<EnumSet<Roshambo>>() {}.getType();
EnumSet<Roshambo> bar = gson.fromJson(json, type); EnumSet<Roshambo> bar = gson.fromJson(json, type);
assertTrue(bar.contains(Roshambo.ROCK)); assertTrue(bar.contains(Roshambo.ROCK));
@ -157,6 +162,18 @@ public class EnumTest extends TestCase {
assertFalse(bar.contains(Roshambo.SCISSORS)); assertFalse(bar.contains(Roshambo.SCISSORS));
} }
public void testEnumMap() throws Exception {
EnumMap<MyEnum, String> map = new EnumMap<MyEnum, String>(MyEnum.class);
map.put(MyEnum.VALUE1, "test");
String json = gson.toJson(map);
assertEquals("{\"VALUE1\":\"test\"}", json);
Type type = new TypeToken<EnumMap<MyEnum, String>>() {}.getType();
EnumMap<?, ?> actualMap = gson.fromJson("{\"VALUE1\":\"test\"}", type);
Map<?, ?> expectedMap = Collections.singletonMap(MyEnum.VALUE1, "test");
assertEquals(expectedMap, actualMap);
}
public enum Roshambo { public enum Roshambo {
ROCK { ROCK {
@Override Roshambo defeats() { @Override Roshambo defeats() {