DATACMNS-1246 - Minor optimization in QueryExecutorMethodInterceptor.

We now prevent the superfluous creation of a MethodParameter and TypeDescriptor instance in repository method execution in case the value to be returned already is an instance of the expected method return type.
This commit is contained in:
Oliver Gierke
2018-01-18 17:27:57 +01:00
parent 7c0ec77e40
commit 69cb5c6653
3 changed files with 37 additions and 25 deletions

View File

@@ -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)) {

View File

@@ -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 {

View File

@@ -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<Entity> 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<Entity> optional = (Optional<Entity>) 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<Entity> optional = (com.google.common.base.Optional<Entity>) 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<Entity, Long> {