diff --git a/src/main/java/org/springframework/data/repository/core/support/QueryExecutionResultHandler.java b/src/main/java/org/springframework/data/repository/core/support/QueryExecutionResultHandler.java index 284e8e8f1..c0f38e352 100644 --- a/src/main/java/org/springframework/data/repository/core/support/QueryExecutionResultHandler.java +++ b/src/main/java/org/springframework/data/repository/core/support/QueryExecutionResultHandler.java @@ -15,10 +15,12 @@ */ package org.springframework.data.repository.core.support; +import java.lang.reflect.Method; import java.util.Map; import java.util.Optional; import org.springframework.core.CollectionFactory; +import org.springframework.core.MethodParameter; import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.core.convert.support.GenericConversionService; @@ -50,6 +52,26 @@ class QueryExecutionResultHandler { this.conversionService = conversionService; } + /** + * Post-processes the given result of a query invocation to match the return type of the given method. + * + * @param result can be {@literal null}. + * @param metho must not be {@literal null}. + * @return + */ + @Nullable + public Object postProcessInvocationResult(@Nullable Object result, Method method) { + + if (method.getReturnType().isInstance(result)) { + return result; + } + + MethodParameter parameter = new MethodParameter(method, -1); + TypeDescriptor methodReturnTypeDescriptor = TypeDescriptor.nested(parameter, 0); + + return postProcessInvocationResult(result, methodReturnTypeDescriptor); + } + /** * Post-processes the given result of a query invocation to the given type. * @@ -58,7 +80,7 @@ class QueryExecutionResultHandler { * @return */ @Nullable - public Object postProcessInvocationResult(@Nullable Object result, @Nullable TypeDescriptor returnTypeDescriptor) { + Object postProcessInvocationResult(@Nullable Object result, @Nullable TypeDescriptor returnTypeDescriptor) { if (returnTypeDescriptor == null) { return result; diff --git a/src/main/java/org/springframework/data/repository/core/support/RepositoryFactorySupport.java b/src/main/java/org/springframework/data/repository/core/support/RepositoryFactorySupport.java index dbdc42c2a..22ff9a0ee 100644 --- a/src/main/java/org/springframework/data/repository/core/support/RepositoryFactorySupport.java +++ b/src/main/java/org/springframework/data/repository/core/support/RepositoryFactorySupport.java @@ -41,9 +41,7 @@ import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; -import org.springframework.core.MethodParameter; import org.springframework.core.ResolvableType; -import org.springframework.core.convert.TypeDescriptor; import org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor; import org.springframework.data.projection.ProjectionFactory; import org.springframework.data.projection.SpelAwareProxyProjectionFactory; @@ -579,12 +577,7 @@ public abstract class RepositoryFactorySupport implements BeanClassLoaderAware, Object result = doInvoke(invocation); - // Looking up the TypeDescriptor for the return type - yes, this way o.O - Method method = invocation.getMethod(); - MethodParameter parameter = new MethodParameter(method, -1); - TypeDescriptor methodReturnTypeDescriptor = TypeDescriptor.nested(parameter, 0); - - return resultHandler.postProcessInvocationResult(result, methodReturnTypeDescriptor); + return resultHandler.postProcessInvocationResult(result, invocation.getMethod()); } @Nullable diff --git a/src/test/java/org/springframework/data/repository/core/support/QueryExecutionResultHandlerUnitTests.java b/src/test/java/org/springframework/data/repository/core/support/QueryExecutionResultHandlerUnitTests.java index 403f91df3..63699b469 100755 --- a/src/test/java/org/springframework/data/repository/core/support/QueryExecutionResultHandlerUnitTests.java +++ b/src/test/java/org/springframework/data/repository/core/support/QueryExecutionResultHandlerUnitTests.java @@ -35,7 +35,6 @@ import java.util.stream.Collectors; import org.junit.Test; import org.reactivestreams.Publisher; -import org.springframework.core.MethodParameter; import org.springframework.core.convert.TypeDescriptor; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.repository.Repository; @@ -54,16 +53,16 @@ public class QueryExecutionResultHandlerUnitTests { @Test // DATACMNS-610 public void convertsListsToSet() throws Exception { - TypeDescriptor descriptor = getTypeDescriptorFor("set"); + Method method = getMethod("set"); List source = Collections.singletonList(new Entity()); - assertThat(handler.postProcessInvocationResult(source, descriptor)).isInstanceOf(Set.class); + assertThat(handler.postProcessInvocationResult(source, method)).isInstanceOf(Set.class); } @Test // DATACMNS-483 public void turnsNullIntoJdk8Optional() throws Exception { - Object result = handler.postProcessInvocationResult(null, getTypeDescriptorFor("jdk8Optional")); + Object result = handler.postProcessInvocationResult(null, getMethod("jdk8Optional")); assertThat(result).isEqualTo(Optional.empty()); } @@ -73,7 +72,7 @@ public class QueryExecutionResultHandlerUnitTests { Entity entity = new Entity(); - Object result = handler.postProcessInvocationResult(entity, getTypeDescriptorFor("jdk8Optional")); + Object result = handler.postProcessInvocationResult(entity, getMethod("jdk8Optional")); assertThat(result).isInstanceOf(Optional.class); Optional optional = (Optional) result; @@ -83,7 +82,7 @@ public class QueryExecutionResultHandlerUnitTests { @Test // DATACMNS-483 public void turnsNullIntoGuavaOptional() throws Exception { - Object result = handler.postProcessInvocationResult(null, getTypeDescriptorFor("guavaOptional")); + Object result = handler.postProcessInvocationResult(null, getMethod("guavaOptional")); assertThat(result).isEqualTo(com.google.common.base.Optional.absent()); } @@ -93,7 +92,7 @@ public class QueryExecutionResultHandlerUnitTests { Entity entity = new Entity(); - Object result = handler.postProcessInvocationResult(entity, getTypeDescriptorFor("guavaOptional")); + Object result = handler.postProcessInvocationResult(entity, getMethod("guavaOptional")); assertThat(result).isInstanceOf(com.google.common.base.Optional.class); com.google.common.base.Optional optional = (com.google.common.base.Optional) result; @@ -102,7 +101,7 @@ public class QueryExecutionResultHandlerUnitTests { @Test // DATACMNS-917 public void defaultsNullToEmptyMap() throws Exception { - assertThat(handler.postProcessInvocationResult(null, getTypeDescriptorFor("map"))).isInstanceOf(Map.class); + assertThat(handler.postProcessInvocationResult(null, getMethod("map"))).isInstanceOf(Map.class); } @Test // DATACMNS-836 @@ -111,7 +110,7 @@ public class QueryExecutionResultHandlerUnitTests { Single entity = Single.just(new Entity()); - Object result = handler.postProcessInvocationResult(entity, getTypeDescriptorFor("publisher")); + Object result = handler.postProcessInvocationResult(entity, getMethod("publisher")); assertThat(result).isInstanceOf(Publisher.class); Mono mono = Mono.from((Publisher) result); @@ -124,7 +123,7 @@ public class QueryExecutionResultHandlerUnitTests { Single entity = Single.just(new Entity()); - Object result = handler.postProcessInvocationResult(entity, getTypeDescriptorFor("mono")); + Object result = handler.postProcessInvocationResult(entity, getMethod("mono")); assertThat(result).isInstanceOf(Mono.class); Mono mono = (Mono) result; @@ -137,7 +136,7 @@ public class QueryExecutionResultHandlerUnitTests { Single entity = Single.just(new Entity()); - Object result = handler.postProcessInvocationResult(entity, getTypeDescriptorFor("flux")); + Object result = handler.postProcessInvocationResult(entity, getMethod("flux")); assertThat(result).isInstanceOf(Flux.class); Flux flux = (Flux) result; @@ -150,7 +149,7 @@ public class QueryExecutionResultHandlerUnitTests { Observable entity = Observable.just(new Entity()); - Object result = handler.postProcessInvocationResult(entity, getTypeDescriptorFor("publisher")); + Object result = handler.postProcessInvocationResult(entity, getMethod("publisher")); assertThat(result).isInstanceOf(Publisher.class); Mono mono = Mono.from((Publisher) result); @@ -163,7 +162,7 @@ public class QueryExecutionResultHandlerUnitTests { Observable entity = Observable.just(new Entity()); - Object result = handler.postProcessInvocationResult(entity, getTypeDescriptorFor("mono")); + Object result = handler.postProcessInvocationResult(entity, getMethod("mono")); assertThat(result).isInstanceOf(Mono.class); Mono mono = (Mono) result; @@ -176,7 +175,7 @@ public class QueryExecutionResultHandlerUnitTests { Observable entity = Observable.just(new Entity()); - Object result = handler.postProcessInvocationResult(entity, getTypeDescriptorFor("flux")); + Object result = handler.postProcessInvocationResult(entity, getMethod("flux")); assertThat(result).isInstanceOf(Flux.class); Flux flux = (Flux) result; @@ -189,7 +188,7 @@ public class QueryExecutionResultHandlerUnitTests { Observable entity = Observable.just(new Entity()); - Object result = handler.postProcessInvocationResult(entity, getTypeDescriptorFor("single")); + Object result = handler.postProcessInvocationResult(entity, getMethod("single")); assertThat(result).isInstanceOf(Single.class); Single single = (Single) result; @@ -202,7 +201,7 @@ public class QueryExecutionResultHandlerUnitTests { Single entity = Single.just(new Entity()); - Object result = handler.postProcessInvocationResult(entity, getTypeDescriptorFor("observable")); + Object result = handler.postProcessInvocationResult(entity, getMethod("observable")); assertThat(result).isInstanceOf(Observable.class); Observable observable = (Observable) result; @@ -215,7 +214,7 @@ public class QueryExecutionResultHandlerUnitTests { Mono entity = Mono.just(new Entity()); - Object result = handler.postProcessInvocationResult(entity, getTypeDescriptorFor("single")); + Object result = handler.postProcessInvocationResult(entity, getMethod("single")); assertThat(result).isInstanceOf(Single.class); Single single = (Single) result; @@ -228,7 +227,7 @@ public class QueryExecutionResultHandlerUnitTests { Mono entity = Mono.just(new Entity()); - Object result = handler.postProcessInvocationResult(entity, getTypeDescriptorFor("completable")); + Object result = handler.postProcessInvocationResult(entity, getMethod("completable")); assertThat(result).isInstanceOf(Completable.class); Completable completable = (Completable) result; @@ -241,7 +240,7 @@ public class QueryExecutionResultHandlerUnitTests { Mono entity = Mono.error(new InvalidDataAccessApiUsageException("err")); - Object result = handler.postProcessInvocationResult(entity, getTypeDescriptorFor("completable")); + Object result = handler.postProcessInvocationResult(entity, getMethod("completable")); assertThat(result).isInstanceOf(Completable.class); Completable completable = (Completable) result; @@ -254,7 +253,7 @@ public class QueryExecutionResultHandlerUnitTests { Completable entity = Completable.complete(); - Object result = handler.postProcessInvocationResult(entity, getTypeDescriptorFor("mono")); + Object result = handler.postProcessInvocationResult(entity, getMethod("mono")); assertThat(result).isInstanceOf(Mono.class); Mono mono = (Mono) result; @@ -267,7 +266,7 @@ public class QueryExecutionResultHandlerUnitTests { Completable entity = Completable.error(new InvalidDataAccessApiUsageException("err")); - Object result = handler.postProcessInvocationResult(entity, getTypeDescriptorFor("mono")); + Object result = handler.postProcessInvocationResult(entity, getMethod("mono")); assertThat(result).isInstanceOf(Mono.class); Mono mono = (Mono) result; @@ -281,7 +280,7 @@ public class QueryExecutionResultHandlerUnitTests { Mono entity = Mono.just(new Entity()); - Object result = handler.postProcessInvocationResult(entity, getTypeDescriptorFor("observable")); + Object result = handler.postProcessInvocationResult(entity, getMethod("observable")); assertThat(result).isInstanceOf(Observable.class); Observable observable = (Observable) result; @@ -294,7 +293,7 @@ public class QueryExecutionResultHandlerUnitTests { Flux entity = Flux.just(new Entity()); - Object result = handler.postProcessInvocationResult(entity, getTypeDescriptorFor("single")); + Object result = handler.postProcessInvocationResult(entity, getMethod("single")); assertThat(result).isInstanceOf(Single.class); Single single = (Single) result; @@ -307,7 +306,7 @@ public class QueryExecutionResultHandlerUnitTests { Flux entity = Flux.just(new Entity()); - Object result = handler.postProcessInvocationResult(entity, getTypeDescriptorFor("observable")); + Object result = handler.postProcessInvocationResult(entity, getMethod("observable")); assertThat(result).isInstanceOf(Observable.class); Observable observable = (Observable) result; @@ -320,7 +319,7 @@ public class QueryExecutionResultHandlerUnitTests { Flux entity = Flux.just(new Entity()); - Object result = handler.postProcessInvocationResult(entity, getTypeDescriptorFor("mono")); + Object result = handler.postProcessInvocationResult(entity, getMethod("mono")); assertThat(result).isInstanceOf(Mono.class); Mono mono = (Mono) result; @@ -333,7 +332,7 @@ public class QueryExecutionResultHandlerUnitTests { Mono entity = Mono.just(new Entity()); - Object result = handler.postProcessInvocationResult(entity, getTypeDescriptorFor("flux")); + Object result = handler.postProcessInvocationResult(entity, getMethod("flux")); assertThat(result).isInstanceOf(Flux.class); Flux flux = (Flux) result; @@ -363,12 +362,8 @@ public class QueryExecutionResultHandlerUnitTests { it -> assertThat(it.stream().collect(Collectors.toList())).isEqualTo(source)); } - private static TypeDescriptor getTypeDescriptorFor(String methodName) throws Exception { - - Method method = Sample.class.getMethod(methodName); - MethodParameter parameter = new MethodParameter(method, -1); - - return TypeDescriptor.nested(parameter, 0); + private static Method getMethod(String methodName) throws Exception { + return Sample.class.getMethod(methodName); } static interface Sample extends Repository {