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 38acd529f..8fe668341 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,14 +15,17 @@ */ package org.springframework.data.repository.core.support; +import java.lang.reflect.Method; import java.util.Map; 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; import org.springframework.data.repository.util.NullableWrapper; import org.springframework.data.repository.util.QueryExecutionConverters; +import org.springframework.util.Assert; /** * Simple domain service to convert query results into a dedicated type. @@ -46,6 +49,27 @@ 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 method must not be {@literal null}. + * @return + */ + public Object postProcessInvocationResult(Object result, Method method) { + + Assert.notNull(method, "Method must not be null!"); + + 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. * @@ -53,7 +77,7 @@ class QueryExecutionResultHandler { * @param returnTypeDesciptor can be {@literal null}, if so, no conversion is performed. * @return */ - public Object postProcessInvocationResult(Object result, TypeDescriptor returnTypeDesciptor) { + Object postProcessInvocationResult(Object result, TypeDescriptor returnTypeDesciptor) { if (returnTypeDesciptor == null) { return result; @@ -73,7 +97,8 @@ class QueryExecutionResultHandler { if (result != null) { return conversionService.canConvert(result.getClass(), expectedReturnType) - ? conversionService.convert(result, expectedReturnType) : result; + ? conversionService.convert(result, expectedReturnType) + : result; } if (Map.class.equals(expectedReturnType)) { 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 1780c32b4..af7a87fe8 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 @@ -34,8 +34,6 @@ import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.core.GenericTypeResolver; -import org.springframework.core.MethodParameter; -import org.springframework.core.convert.TypeDescriptor; import org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor; import org.springframework.data.projection.ProjectionFactory; import org.springframework.data.projection.SpelAwareProxyProjectionFactory; @@ -476,12 +474,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()); } private Object doInvoke(MethodInvocation invocation) throws Throwable { 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 c122f5aaf..901e0097b 100644 --- a/src/test/java/org/springframework/data/repository/core/support/QueryExecutionResultHandlerUnitTests.java +++ b/src/test/java/org/springframework/data/repository/core/support/QueryExecutionResultHandlerUnitTests.java @@ -26,8 +26,6 @@ import java.util.Optional; import java.util.Set; import org.junit.Test; -import org.springframework.core.MethodParameter; -import org.springframework.core.convert.TypeDescriptor; import org.springframework.data.repository.Repository; /** @@ -42,16 +40,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), is(instanceOf(Set.class))); + assertThat(handler.postProcessInvocationResult(source, method), is(instanceOf(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, is((Object) Optional.empty())); } @@ -61,7 +59,7 @@ public class QueryExecutionResultHandlerUnitTests { Entity entity = new Entity(); - Object result = handler.postProcessInvocationResult(entity, getTypeDescriptorFor("jdk8Optional")); + Object result = handler.postProcessInvocationResult(entity, getMethod("jdk8Optional")); assertThat(result, is(instanceOf(Optional.class))); Optional optional = (Optional) result; @@ -71,7 +69,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, is((Object) com.google.common.base.Optional.absent())); } @@ -81,7 +79,7 @@ public class QueryExecutionResultHandlerUnitTests { Entity entity = new Entity(); - Object result = handler.postProcessInvocationResult(entity, getTypeDescriptorFor("guavaOptional")); + Object result = handler.postProcessInvocationResult(entity, getMethod("guavaOptional")); assertThat(result, is(instanceOf(com.google.common.base.Optional.class))); com.google.common.base.Optional optional = (com.google.common.base.Optional) result; @@ -90,15 +88,11 @@ public class QueryExecutionResultHandlerUnitTests { @Test // DATACMNS-917 public void defaultsNullToEmptyMap() throws Exception { - assertThat(handler.postProcessInvocationResult(null, getTypeDescriptorFor("map")), is(instanceOf(Map.class))); + assertThat(handler.postProcessInvocationResult(null, getMethod("map")), is(instanceOf(Map.class))); } - 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 {