diff --git a/gradle.properties b/gradle.properties index 3568e6e..a5cb525 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ junitVersion=4.12 -vavrVersion=1.0.0-SNAPSHOT +vavrVersion=0.10.3 gsonVersion=2.8.0 diff --git a/src/main/java/io/vavr/gson/JsonArrayConverter.java b/src/main/java/io/vavr/gson/ArrayTypeConverter.java similarity index 96% rename from src/main/java/io/vavr/gson/JsonArrayConverter.java rename to src/main/java/io/vavr/gson/ArrayTypeConverter.java index 7ae3f51..298a540 100644 --- a/src/main/java/io/vavr/gson/JsonArrayConverter.java +++ b/src/main/java/io/vavr/gson/ArrayTypeConverter.java @@ -12,7 +12,7 @@ import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; -abstract class JsonArrayConverter implements JsonSerializer, JsonDeserializer { +abstract class ArrayTypeConverter implements JsonSerializer, JsonDeserializer { private static final Type[] EMPTY_TYPES = new Type[0]; diff --git a/src/main/java/io/vavr/gson/JsonObjectConverter.java b/src/main/java/io/vavr/gson/JsonObjectConverter.java deleted file mode 100644 index 20047cb..0000000 --- a/src/main/java/io/vavr/gson/JsonObjectConverter.java +++ /dev/null @@ -1,44 +0,0 @@ -/* __ __ __ __ __ ___ - * \ \ / / \ \ / / __/ - * \ \/ / /\ \ \/ / / - * \____/__/ \__\____/__/.ɪᴏ - * ᶜᵒᵖʸʳᶦᵍʰᵗ ᵇʸ ᵛᵃᵛʳ ⁻ ˡᶦᶜᵉⁿˢᵉᵈ ᵘⁿᵈᵉʳ ᵗʰᵉ ᵃᵖᵃᶜʰᵉ ˡᶦᶜᵉⁿˢᵉ ᵛᵉʳˢᶦᵒⁿ ᵗʷᵒ ᵈᵒᵗ ᶻᵉʳᵒ - */ -package io.vavr.gson; - -import com.google.gson.*; -import io.vavr.collection.Map; - -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; - -abstract class JsonObjectConverter implements JsonSerializer, JsonDeserializer { - - private static final Type[] EMPTY_TYPES = new Type[0]; - - abstract T fromJsonObject(JsonObject arr, Type type, Type[] subTypes, JsonDeserializationContext ctx) throws JsonParseException; - abstract Map toMap(T src); - - @Override - public T deserialize(JsonElement json, Type type, JsonDeserializationContext ctx) throws JsonParseException { - if (json.isJsonObject()) { - if (type instanceof ParameterizedType) { - ParameterizedType parameterizedType = (ParameterizedType) type; - Type[] types = parameterizedType.getActualTypeArguments(); - return fromJsonObject(json.getAsJsonObject(), type, types, ctx); - } else { - return fromJsonObject(json.getAsJsonObject(), type, EMPTY_TYPES, ctx); - } - } else { - throw new JsonParseException("object expected"); - } - } - - @Override - public JsonElement serialize(T src, Type type, JsonSerializationContext ctx) { - return toMap(src).foldLeft(new JsonObject(), (a, e) -> { - a.add(ctx.serialize(e._1).getAsString(), ctx.serialize(e._2)); - return a; - }); - } -} diff --git a/src/main/java/io/vavr/gson/MapConverter.java b/src/main/java/io/vavr/gson/MapConverter.java index 9724f64..9632d17 100644 --- a/src/main/java/io/vavr/gson/MapConverter.java +++ b/src/main/java/io/vavr/gson/MapConverter.java @@ -6,37 +6,94 @@ */ package io.vavr.gson; -import com.google.gson.*; -import io.vavr.Tuple; -import io.vavr.Tuple2; -import io.vavr.collection.Map; - +import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; -class MapConverter> extends JsonObjectConverter { +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.reflect.TypeToken; +import io.vavr.Tuple; +import io.vavr.Tuple2; +import io.vavr.collection.Map; +import io.vavr.collection.Traversable; +import io.vavr.collection.Vector; - private final Function>, Map> factory; +class MapConverter> extends MapTypeConverter { - MapConverter(Function>, Map> factory) { + private final Function>, Map> factory; + + MapConverter(Function>, Map> factory) { this.factory = factory; } @Override @SuppressWarnings("unchecked") T fromJsonObject(JsonObject obj, Type type, Type[] subTypes, JsonDeserializationContext ctx) throws JsonParseException { - Function, Tuple2> mapper; + Function, Tuple2> mapper; if (subTypes.length == 2) { - mapper = e -> Tuple.of(ctx.deserialize(new JsonPrimitive(e.getKey()), subTypes[0]), ctx.deserialize(e.getValue(), subTypes[1])); + mapper = e -> convert(ctx, e, subTypes[0], subTypes[1]); } else { - mapper = e -> Tuple.of(e.getKey(), e.getValue()); + mapper = e -> Tuple.of((K) e.getKey(), (V) e.getValue()); } - return (T) factory.apply(obj.entrySet().stream().map(mapper).collect(Collectors.toList())); + final Set> entries = obj.entrySet(); + final Iterable> collect = entries.stream().map(mapper).collect(Collectors.toList()); + return (T) factory.apply(collect); + } + + @Override + @SuppressWarnings("unchecked") + T fromJsonArray(JsonArray arr, Type type, Type[] subTypes, JsonDeserializationContext ctx) throws JsonParseException { + final Awkward tuple2KV = new Awkward(Tuple2.class, subTypes); + final Type traversableType = new TypeToken>() { + }.getType(); + final Awkward traversableTuple2KV = new Awkward(traversableType, tuple2KV); + final TraversableConverter>> traversableConverter = new TraversableConverter<>(Vector::ofAll); + final Traversable> tuple2s = traversableConverter.fromJsonArray(arr, traversableTuple2KV, traversableTuple2KV.getActualTypeArguments(), ctx); + return (T) factory.apply(tuple2s); + } + + private Tuple2 convert(JsonDeserializationContext ctx, java.util.Map.Entry e, Type keyType, Type valueType) { + final JsonPrimitive json = new JsonPrimitive(e.getKey()); + final K key = ctx.deserialize(json, keyType); + final V value = ctx.deserialize(e.getValue(), valueType); + return Tuple.of(key, value); } @Override Map toMap(T src) { return src; } + + private static final class Awkward implements ParameterizedType { + + private final Type rawType; + private final Type[] subTypes; + + private Awkward(Type rawType, Type... subTypes) { + this.rawType = rawType; + this.subTypes = subTypes; + } + + @Override + public Type[] getActualTypeArguments() { + return subTypes; + } + + @Override + public Type getRawType() { + return rawType; + } + + @Override + public Type getOwnerType() { + return null; + } + } } diff --git a/src/main/java/io/vavr/gson/MapTypeConverter.java b/src/main/java/io/vavr/gson/MapTypeConverter.java new file mode 100644 index 0000000..0730009 --- /dev/null +++ b/src/main/java/io/vavr/gson/MapTypeConverter.java @@ -0,0 +1,81 @@ +/* __ __ __ __ __ ___ + * \ \ / / \ \ / / __/ + * \ \/ / /\ \ \/ / / + * \____/__/ \__\____/__/.ɪᴏ + * ᶜᵒᵖʸʳᶦᵍʰᵗ ᵇʸ ᵛᵃᵛʳ ⁻ ˡᶦᶜᵉⁿˢᵉᵈ ᵘⁿᵈᵉʳ ᵗʰᵉ ᵃᵖᵃᶜʰᵉ ˡᶦᶜᵉⁿˢᵉ ᵛᵉʳˢᶦᵒⁿ ᵗʷᵒ ᵈᵒᵗ ᶻᵉʳᵒ + */ +package io.vavr.gson; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; + +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import io.vavr.collection.Map; + +import static jdk.nashorn.internal.runtime.JSType.isPrimitive; + +abstract class MapTypeConverter implements JsonSerializer, JsonDeserializer { + + private static final Type[] EMPTY_TYPES = new Type[0]; + + abstract T fromJsonObject(JsonObject arr, Type type, Type[] subTypes, JsonDeserializationContext ctx) throws JsonParseException; + + abstract T fromJsonArray(JsonArray arr, Type type, Type[] subTypes, JsonDeserializationContext ctx) throws JsonParseException; + + abstract Map toMap(T src); + + @Override + public T deserialize(JsonElement json, Type type, JsonDeserializationContext ctx) throws JsonParseException { + if (json.isJsonObject()) { + if (type instanceof ParameterizedType) { + ParameterizedType parameterizedType = (ParameterizedType) type; + Type[] types = parameterizedType.getActualTypeArguments(); + return fromJsonObject(json.getAsJsonObject(), type, types, ctx); + } else { + return fromJsonObject(json.getAsJsonObject(), type, EMPTY_TYPES, ctx); + } + } else if (json.isJsonArray()) { + // list of tuples + if (type instanceof ParameterizedType) { + ParameterizedType parameterizedType = (ParameterizedType) type; + Type[] types = parameterizedType.getActualTypeArguments(); + return fromJsonArray(json.getAsJsonArray(), parameterizedType, types, ctx); + } else { + throw new JsonParseException("unsupported non-parameterised types for complex map keys"); + } + } else { + throw new JsonParseException("object or array expected"); + } + } + + @Override + public JsonElement serialize(T src, Type type, JsonSerializationContext ctx) { + final Map tuple2s = toMap(src); + if (tuple2s.isEmpty()) { + return new JsonObject(); + } else { + // test the first element + final Object o = tuple2s.head()._1(); + // primitives are fine + if (isPrimitive(o)) { + return tuple2s.foldLeft(new JsonObject(), (a, e) -> { + a.add(ctx.serialize(e._1).getAsString(), ctx.serialize(e._2)); + return a; + }); + } else { + //complex object key serialisation + return tuple2s.foldLeft(new JsonArray(), (a, e) -> { + a.add(ctx.serialize(e)); + return a; + }); + } + } + } +} diff --git a/src/main/java/io/vavr/gson/MultimapConverter.java b/src/main/java/io/vavr/gson/MultimapConverter.java index 36b94f4..8554569 100644 --- a/src/main/java/io/vavr/gson/MultimapConverter.java +++ b/src/main/java/io/vavr/gson/MultimapConverter.java @@ -6,7 +6,18 @@ */ package io.vavr.gson; -import com.google.gson.*; +import java.lang.reflect.Type; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; import io.vavr.Function1; import io.vavr.Tuple; import io.vavr.Tuple2; @@ -15,13 +26,7 @@ import io.vavr.collection.Map; import io.vavr.collection.Multimap; -import java.lang.reflect.Type; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; - -class MultimapConverter> extends JsonObjectConverter { +class MultimapConverter> extends MapTypeConverter { private final Function>, Multimap> factory; @@ -41,6 +46,12 @@ T fromJsonObject(JsonObject obj, Type type, Type[] subTypes, JsonDeserialization return (T) factory.apply(obj.entrySet().stream().flatMap(mapper).collect(Collectors.toList())); } + @Override + @SuppressWarnings("unchecked") + T fromJsonArray(JsonArray arr, Type type, Type[] subTypes, JsonDeserializationContext ctx) throws JsonParseException { + throw new UnsupportedOperationException("Array types not supported for Multimaps"); + } + @Override @SuppressWarnings("unchecked") Map> toMap(T src) { diff --git a/src/main/java/io/vavr/gson/OptionConverter.java b/src/main/java/io/vavr/gson/OptionConverter.java index cd6d848..7f6dea7 100644 --- a/src/main/java/io/vavr/gson/OptionConverter.java +++ b/src/main/java/io/vavr/gson/OptionConverter.java @@ -15,7 +15,7 @@ import java.lang.reflect.Type; -class OptionConverter extends JsonArrayConverter> { +class OptionConverter extends ArrayTypeConverter> { @Override Option fromJsonArray(JsonArray arr, Type type, Type[] subTypes, JsonDeserializationContext ctx) throws JsonParseException { diff --git a/src/main/java/io/vavr/gson/TraversableConverter.java b/src/main/java/io/vavr/gson/TraversableConverter.java index ed632c0..d0f2552 100644 --- a/src/main/java/io/vavr/gson/TraversableConverter.java +++ b/src/main/java/io/vavr/gson/TraversableConverter.java @@ -15,7 +15,7 @@ import java.lang.reflect.Type; import java.util.function.Function; -class TraversableConverter> extends JsonArrayConverter { +class TraversableConverter> extends ArrayTypeConverter { private final Function, Traversable> factory; diff --git a/src/main/java/io/vavr/gson/TupleConverter.java b/src/main/java/io/vavr/gson/TupleConverter.java index a0c986c..c443d62 100644 --- a/src/main/java/io/vavr/gson/TupleConverter.java +++ b/src/main/java/io/vavr/gson/TupleConverter.java @@ -16,7 +16,7 @@ import java.lang.reflect.Type; -abstract class TupleConverter extends JsonArrayConverter { +abstract class TupleConverter extends ArrayTypeConverter { static class N0 extends TupleConverter { diff --git a/src/main/java/io/vavr/gson/VavrGson.java b/src/main/java/io/vavr/gson/VavrGson.java index 64398fd..1cb419c 100644 --- a/src/main/java/io/vavr/gson/VavrGson.java +++ b/src/main/java/io/vavr/gson/VavrGson.java @@ -9,6 +9,7 @@ import java.lang.reflect.Type; import java.util.Arrays; import java.util.Objects; +import java.util.function.Function; import com.google.gson.GsonBuilder; import io.vavr.*; @@ -378,10 +379,15 @@ public static Map multiMapTypeAdapters() { public static Map mapTypeAdapters() { return API.Map() .put(Map.class, new MapConverter<>(HashMap::ofEntries)) - .put(SortedMap.class, new MapConverter<>(TreeMap::ofEntries)) + .put(SortedMap.class, new MapConverter<>(VavrGson::getTreeMapMapper)) .put(HashMap.class, new MapConverter<>(HashMap::ofEntries)) .put(LinkedHashMap.class, new MapConverter<>(LinkedHashMap::ofEntries)) - .put(TreeMap.class, new MapConverter<>(TreeMap::ofEntries)); + .put(TreeMap.class, new MapConverter<>(VavrGson::getTreeMapMapper)); + } + + + private static TreeMap getTreeMapMapper(Iterable> i) { + return TreeMap.ofEntries((a, b) -> ((Comparable) a).compareTo(b), i); } public static Map collectionTypeAdapters() { diff --git a/src/test/java/io/vavr/gson/AbstractTest.java b/src/test/java/io/vavr/gson/AbstractTest.java index a69701e..1e3d2a4 100644 --- a/src/test/java/io/vavr/gson/AbstractTest.java +++ b/src/test/java/io/vavr/gson/AbstractTest.java @@ -12,6 +12,7 @@ public class AbstractTest { public static void before() { GsonBuilder builder = new GsonBuilder(); VavrGson.registerAll(builder); + builder = builder.enableComplexMapKeySerialization(); gson = builder.create(); } diff --git a/src/test/java/io/vavr/gson/map/HashMapTest.java b/src/test/java/io/vavr/gson/map/HashMapTest.java index 6c8cf6d..da9439f 100644 --- a/src/test/java/io/vavr/gson/map/HashMapTest.java +++ b/src/test/java/io/vavr/gson/map/HashMapTest.java @@ -1,16 +1,24 @@ package io.vavr.gson.map; +import java.lang.reflect.Type; + import com.google.gson.reflect.TypeToken; import io.vavr.collection.HashMap; +import io.vavr.collection.Map; +import org.junit.Test; -import java.lang.reflect.Type; +public class HashMapTest extends MapLikeTest> { -public class HashMapTest extends MapLikeTest> { @Override HashMap of(Object key, Object value) { return HashMap.of(key, value); } + @Override + Map ofTyped(K key, V value) { + return HashMap.of(key, value); + } + @Override Class clz() { return HashMap.class; @@ -18,11 +26,45 @@ Class clz() { @Override Type type() { - return new TypeToken>(){}.getType(); + return new TypeToken>() { + }.getType(); + } + + @Override + Type intType() { + return new TypeToken>() { + }.getType(); } @Override Type typeWithNestedType() { - return new TypeToken>>(){}.getType(); + return new TypeToken>>() { + }.getType(); + } + + @Override + Type typeWithNestedIntType() { + return new TypeToken>>() { + }.getType(); + } + + @Override + Type getComplexNestedKeyType() { + return new TypeToken>>() { + }.getType(); + } + + @Test + public void deserializeLongKey() { + Map map = gson.fromJson("{\"1\":2}", new TypeToken>(){}.getType()); + assert clz().isAssignableFrom(map.getClass()); + assert map.get(1L).get() == 2; + } + + @Test + public void deserializeDoubleKey() { + Map map = gson.fromJson("{\"1.323\":2}", new TypeToken>(){}.getType()); + assert clz().isAssignableFrom(map.getClass()); + assert map.get(1.323D).get() == 2; } } diff --git a/src/test/java/io/vavr/gson/map/LinkedHashMapTest.java b/src/test/java/io/vavr/gson/map/LinkedHashMapTest.java index db9d02a..c154170 100644 --- a/src/test/java/io/vavr/gson/map/LinkedHashMapTest.java +++ b/src/test/java/io/vavr/gson/map/LinkedHashMapTest.java @@ -1,16 +1,23 @@ package io.vavr.gson.map; +import java.lang.reflect.Type; + import com.google.gson.reflect.TypeToken; import io.vavr.collection.LinkedHashMap; +import io.vavr.collection.Map; -import java.lang.reflect.Type; +public class LinkedHashMapTest extends MapLikeTest> { -public class LinkedHashMapTest extends MapLikeTest> { @Override LinkedHashMap of(Object key, Object value) { return LinkedHashMap.of(key, value); } + @Override + Map ofTyped(K key, V value) { + return LinkedHashMap.of(key, value); + } + @Override Class clz() { return LinkedHashMap.class; @@ -18,11 +25,31 @@ Class clz() { @Override Type type() { - return new TypeToken>(){}.getType(); + return new TypeToken>() { + }.getType(); } @Override Type typeWithNestedType() { - return new TypeToken>>(){}.getType(); + return new TypeToken>>() { + }.getType(); + } + + @Override + Type intType() { + return new TypeToken>() { + }.getType(); + } + + @Override + Type typeWithNestedIntType() { + return new TypeToken>>() { + }.getType(); + } + + @Override + Type getComplexNestedKeyType() { + return new TypeToken>>() { + }.getType(); } } diff --git a/src/test/java/io/vavr/gson/map/MapLikeTest.java b/src/test/java/io/vavr/gson/map/MapLikeTest.java index 0aa726c..9cd0621 100644 --- a/src/test/java/io/vavr/gson/map/MapLikeTest.java +++ b/src/test/java/io/vavr/gson/map/MapLikeTest.java @@ -1,20 +1,34 @@ package io.vavr.gson.map; +import java.lang.reflect.Type; +import java.util.Comparator; +import java.util.Objects; + import com.google.gson.JsonParseException; import com.google.gson.JsonPrimitive; +import io.vavr.collection.HashMap; import io.vavr.collection.Map; import io.vavr.gson.AbstractTest; import org.junit.Test; -import java.lang.reflect.Type; - -public abstract class MapLikeTest> extends AbstractTest { +public abstract class MapLikeTest> extends AbstractTest { abstract T of(Object key, Object value); + + abstract Map ofTyped(K key, V value); + abstract Class clz(); + abstract Type type(); + + abstract Type intType(); + abstract Type typeWithNestedType(); + abstract Type typeWithNestedIntType(); + + abstract Type getComplexNestedKeyType(); + @Test(expected = JsonParseException.class) public void badJson() { gson.fromJson("1", type()); @@ -41,6 +55,13 @@ public void deserialize() { assert map.get("1").get() == 2; } + @Test + public void deserializeIntegerKey() { + Map map = gson.fromJson("{\"1\":2}", intType()); + assert clz().isAssignableFrom(map.getClass()); + assert map.get(1).get() == 2; + } + @Test public void deserializeWithCast() { Map map = gson.fromJson("{\"1\":\"2\"}", type()); @@ -54,4 +75,75 @@ public void deserializeNested() { assert clz().isAssignableFrom(map.get("1").get().getClass()); assert map.get("1").get().get("2").get() == 3; } + + @Test + public void deserializeNestedIntegerKey() { + Map> map = gson.fromJson("{\"1\":{\"2\":3}}", typeWithNestedIntType()); + assert clz().isAssignableFrom(map.get("1").get().getClass()); + assert map.get("1").get().get(2).get() == 3; + } + + @Test + public void deserializeNestedComplexKey() { + final CustomKey innerKey = new CustomKey(3, 4); + final CustomKey outerKey = new CustomKey(1, 2); + Map> map = gson.fromJson("[[{\"a\":1,\"b\":2},[[{\"a\":3,\"b\":4},5]]]]", getComplexNestedKeyType()); + assert clz().isAssignableFrom(map.get(outerKey).get().getClass()); + assert map.get(outerKey).get().get(innerKey).get() == 5; + } + + @Test + public void serializeNestedComplexKey() { + final CustomKey innerKey = new CustomKey(3, 4); + final Map innerMap = ofTyped(innerKey, 5); + final CustomKey outerKey = new CustomKey(1, 2); + final Map> vavrMap = ofTyped(outerKey, innerMap); + Map> map = gson.fromJson(gson.toJson(vavrMap), getComplexNestedKeyType()); + assert clz().isAssignableFrom(map.get(outerKey).get().getClass()); + assert map.get(outerKey).get().get(innerKey).get() == 5; + } + + static final class CustomKey implements Comparable { + + private final int a; + private final int b; + + public CustomKey(int a, int b) { + this.a = a; + this.b = b; + } + + public int getA() { + return a; + } + + public int getB() { + return b; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + CustomKey customKey = (CustomKey) o; + return a == customKey.a && + b == customKey.b; + } + + @Override + public int hashCode() { + return Objects.hash(a, b); + } + + @Override + public int compareTo(CustomKey o) { + return Comparator.comparingInt(CustomKey::getA) + .thenComparing(CustomKey::getB) + .compare(this, o); + } + } } diff --git a/src/test/java/io/vavr/gson/map/MapTest.java b/src/test/java/io/vavr/gson/map/MapTest.java index 5a85958..c9e2411 100644 --- a/src/test/java/io/vavr/gson/map/MapTest.java +++ b/src/test/java/io/vavr/gson/map/MapTest.java @@ -1,17 +1,23 @@ package io.vavr.gson.map; +import java.lang.reflect.Type; + import com.google.gson.reflect.TypeToken; import io.vavr.collection.HashMap; import io.vavr.collection.Map; -import java.lang.reflect.Type; +public class MapTest extends MapLikeTest> { -public class MapTest extends MapLikeTest> { @Override Map of(Object key, Object value) { return HashMap.of(key, value); } + @Override + Map ofTyped(K key, V value) { + return HashMap.of(key, value); + } + @Override Class clz() { return Map.class; @@ -19,11 +25,31 @@ Class clz() { @Override Type type() { - return new TypeToken>(){}.getType(); + return new TypeToken>() { + }.getType(); } @Override Type typeWithNestedType() { - return new TypeToken>>(){}.getType(); + return new TypeToken>>() { + }.getType(); + } + + @Override + Type intType() { + return new TypeToken>() { + }.getType(); + } + + @Override + Type typeWithNestedIntType() { + return new TypeToken>>() { + }.getType(); + } + + @Override + Type getComplexNestedKeyType() { + return new TypeToken>>() { + }.getType(); } } diff --git a/src/test/java/io/vavr/gson/map/SortedMapTest.java b/src/test/java/io/vavr/gson/map/SortedMapTest.java index 051db02..454c8e9 100644 --- a/src/test/java/io/vavr/gson/map/SortedMapTest.java +++ b/src/test/java/io/vavr/gson/map/SortedMapTest.java @@ -1,18 +1,30 @@ package io.vavr.gson.map; +import java.lang.reflect.Type; + import com.google.gson.reflect.TypeToken; +import io.vavr.collection.Map; import io.vavr.collection.SortedMap; import io.vavr.collection.TreeMap; -import java.lang.reflect.Type; +public class SortedMapTest extends MapLikeTest> { -public class SortedMapTest extends MapLikeTest> { @Override @SuppressWarnings("unchecked") SortedMap of(Object key, Object value) { return TreeMap.of((Comparable) key, value); } + @Override + @SuppressWarnings("unchecked") + Map ofTyped(K key, V value) { + if (key instanceof Comparable) { + final Comparable typedKey = (Comparable) key; + final Map of = TreeMap.of(typedKey, value); + return (Map) of; + } else throw new IllegalArgumentException("Must be Comparable"); + } + @Override Class clz() { return SortedMap.class; @@ -20,11 +32,31 @@ Class clz() { @Override Type type() { - return new TypeToken>(){}.getType(); + return new TypeToken>() { + }.getType(); } @Override Type typeWithNestedType() { - return new TypeToken>>(){}.getType(); + return new TypeToken>>() { + }.getType(); + } + + @Override + Type intType() { + return new TypeToken>() { + }.getType(); + } + + @Override + Type typeWithNestedIntType() { + return new TypeToken>>() { + }.getType(); + } + + @Override + Type getComplexNestedKeyType() { + return new TypeToken>>() { + }.getType(); } } diff --git a/src/test/java/io/vavr/gson/map/TreeMapTest.java b/src/test/java/io/vavr/gson/map/TreeMapTest.java index 530c997..c5ae612 100644 --- a/src/test/java/io/vavr/gson/map/TreeMapTest.java +++ b/src/test/java/io/vavr/gson/map/TreeMapTest.java @@ -1,17 +1,29 @@ package io.vavr.gson.map; +import java.lang.reflect.Type; + import com.google.gson.reflect.TypeToken; +import io.vavr.collection.Map; import io.vavr.collection.TreeMap; -import java.lang.reflect.Type; +public class TreeMapTest extends MapLikeTest> { -public class TreeMapTest extends MapLikeTest> { @Override @SuppressWarnings("unchecked") TreeMap of(Object key, Object value) { return TreeMap.of((Comparable) key, value); } + @Override + @SuppressWarnings("unchecked") + Map ofTyped(K key, V value) { + if (key instanceof Comparable) { + final Comparable typedKey = (Comparable) key; + final Map of = TreeMap.of(typedKey, value); + return (Map) of; + } else throw new IllegalArgumentException("Must be Comparable"); + } + @Override Class clz() { return TreeMap.class; @@ -19,11 +31,31 @@ Class clz() { @Override Type type() { - return new TypeToken>(){}.getType(); + return new TypeToken>() { + }.getType(); } @Override Type typeWithNestedType() { - return new TypeToken>>(){}.getType(); + return new TypeToken>>() { + }.getType(); + } + + @Override + Type intType() { + return new TypeToken>() { + }.getType(); + } + + @Override + Type typeWithNestedIntType() { + return new TypeToken>>() { + }.getType(); + } + + @Override + Type getComplexNestedKeyType() { + return new TypeToken>>() { + }.getType(); } }