From 480294bb5c50add969ea7b47df5c6e789cad9caa Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Fri, 2 Feb 2018 16:06:22 +0100 Subject: [PATCH] DATACMNS-1252 - Improved Vavr collection handling to convert between collection types. If a query method now uses e.g. a Vavr Set as return type, we now also use a potential source List as input for the LinkedHashSet, even if that changes the characteristics (duplicate policy etc.) of the result. This is consistent with our general handling of collections as we're using a Spring ConversionService for collection mapping anyway. In general the new conversion algorithm is driven by the expected target type first: - i.v.c.Seq -> i.v.c.List - i.v.c.Set -> i.v.c.LinkedHashSet - i.v.c.Map -> i.v.c.LinkedHashMap If none of the declared types is assignable we fall back to the previous algorithm choosing an implementation as close as possible to the original source value: - j.u.List -> i.v.c.List - j.u.Set -> i.v.c.LinkedHashSet - j.u.Map -> i.v.c.LinkedHashMap Applied the same fixes to the deprecated Javaslang support. Removed some obsolete full qualifications of types. --- .../repository/util/JavaslangCollections.java | 23 ++++++++++++++++--- .../data/repository/util/VavrCollections.java | 23 ++++++++++++++++--- .../QueryExecutionConvertersUnitTests.java | 18 +++++++++++++++ 3 files changed, 58 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/springframework/data/repository/util/JavaslangCollections.java b/src/main/java/org/springframework/data/repository/util/JavaslangCollections.java index 074fd1c93..7e9b5597b 100644 --- a/src/main/java/org/springframework/data/repository/util/JavaslangCollections.java +++ b/src/main/java/org/springframework/data/repository/util/JavaslangCollections.java @@ -109,17 +109,34 @@ class JavaslangCollections { * @see org.springframework.core.convert.converter.GenericConverter#convert(java.lang.Object, org.springframework.core.convert.TypeDescriptor, org.springframework.core.convert.TypeDescriptor) */ @Override - public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { + public Object convert(Object source, TypeDescriptor sourceDescriptor, TypeDescriptor targetDescriptor) { + + Class targetType = targetDescriptor.getType(); + + if (javaslang.collection.Seq.class.isAssignableFrom(targetType)) { + return ReflectionUtils.invokeMethod(LIST_FACTORY_METHOD, null, source); + } + + if (javaslang.collection.Set.class.isAssignableFrom(targetType)) { + return ReflectionUtils.invokeMethod(SET_FACTORY_METHOD, null, source); + } + + if (javaslang.collection.Map.class.isAssignableFrom(targetType)) { + return ReflectionUtils.invokeMethod(MAP_FACTORY_METHOD, null, source); + } + + // No dedicated type asked for, probably Traversable. + // Try to stay as close to the source value. if (source instanceof List) { return ReflectionUtils.invokeMethod(LIST_FACTORY_METHOD, null, source); } - if (source instanceof java.util.Set) { + if (source instanceof Set) { return ReflectionUtils.invokeMethod(SET_FACTORY_METHOD, null, source); } - if (source instanceof java.util.Map) { + if (source instanceof Map) { return ReflectionUtils.invokeMethod(MAP_FACTORY_METHOD, null, source); } diff --git a/src/main/java/org/springframework/data/repository/util/VavrCollections.java b/src/main/java/org/springframework/data/repository/util/VavrCollections.java index e1de51c96..872e164bc 100644 --- a/src/main/java/org/springframework/data/repository/util/VavrCollections.java +++ b/src/main/java/org/springframework/data/repository/util/VavrCollections.java @@ -110,17 +110,34 @@ class VavrCollections { * @see org.springframework.core.convert.converter.GenericConverter#convert(java.lang.Object, org.springframework.core.convert.TypeDescriptor, org.springframework.core.convert.TypeDescriptor) */ @Override - public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { + public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetDescriptor) { + + Class targetType = targetDescriptor.getType(); + + if (io.vavr.collection.Seq.class.isAssignableFrom(targetType)) { + return ReflectionUtils.invokeMethod(LIST_FACTORY_METHOD, null, source); + } + + if (io.vavr.collection.Set.class.isAssignableFrom(targetType)) { + return ReflectionUtils.invokeMethod(SET_FACTORY_METHOD, null, source); + } + + if (io.vavr.collection.Map.class.isAssignableFrom(targetType)) { + return ReflectionUtils.invokeMethod(MAP_FACTORY_METHOD, null, source); + } + + // No dedicated type asked for, probably Traversable. + // Try to stay as close to the source value. if (source instanceof List) { return ReflectionUtils.invokeMethod(LIST_FACTORY_METHOD, null, source); } - if (source instanceof java.util.Set) { + if (source instanceof Set) { return ReflectionUtils.invokeMethod(SET_FACTORY_METHOD, null, source); } - if (source instanceof java.util.Map) { + if (source instanceof Map) { return ReflectionUtils.invokeMethod(MAP_FACTORY_METHOD, null, source); } diff --git a/src/test/java/org/springframework/data/repository/util/QueryExecutionConvertersUnitTests.java b/src/test/java/org/springframework/data/repository/util/QueryExecutionConvertersUnitTests.java index b67e1d902..226c752c5 100644 --- a/src/test/java/org/springframework/data/repository/util/QueryExecutionConvertersUnitTests.java +++ b/src/test/java/org/springframework/data/repository/util/QueryExecutionConvertersUnitTests.java @@ -323,6 +323,24 @@ public class QueryExecutionConvertersUnitTests { assertThat(result, is(vavrOptionNone())); } + @Test // DATAJPA-1258 + public void convertsJavaListsToVavrSet() { + + List source = Collections.singletonList("foo"); + + assertThat(conversionService.convert(source, io.vavr.collection.Set.class), + is(instanceOf(io.vavr.collection.Set.class))); + } + + @Test // DATAJPA-1258 + public void convertsJavaListsToJavaslangSet() { + + List source = Collections.singletonList("foo"); + + assertThat(conversionService.convert(source, javaslang.collection.Set.class), + is(instanceOf(javaslang.collection.Set.class))); + } + // Vavr @SuppressWarnings("unchecked")