DATACMNS-610 - Extracted QueryExecutionResultHandler from RepositoryFactorySupport.

To be able to verify the conversion of List based query execution results into Sets I extracted a QueryExecutionResultHandler that applies the already implemented handling for Optional types and eventually general prost processing in case the return type declared at the repository query method doesn't match the returned value.

Added additional unit tests for Optional handling.
This commit is contained in:
Oliver Gierke
2014-12-04 20:25:11 +01:00
parent 5b1b73b297
commit d8781888d8
3 changed files with 205 additions and 30 deletions

View File

@@ -0,0 +1,78 @@
/*
* Copyright 2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.repository.core.support;
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;
/**
* Simple domain service to convert query results into a dedicated type.
*
* @author Oliver Gierke
*/
class QueryExecutionResultHandler {
private static final TypeDescriptor WRAPPER_TYPE = TypeDescriptor.valueOf(NullableWrapper.class);
private final GenericConversionService conversionService;
/**
* Creates a new {@link QueryExecutionResultHandler}.
*/
public QueryExecutionResultHandler() {
GenericConversionService conversionService = new DefaultConversionService();
QueryExecutionConverters.registerConvertersIn(conversionService);
this.conversionService = conversionService;
}
/**
* Post-processes the given result of a query invocation to the given type.
*
* @param result can be {@literal null}.
* @param returnTypeDesciptor can be {@literal null}, if so, no conversion is performed.
* @return
*/
public Object postProcessInvocationResult(Object result, TypeDescriptor returnTypeDesciptor) {
if (returnTypeDesciptor == null) {
return result;
}
Class<?> expectedReturnType = returnTypeDesciptor.getType();
if (result != null && expectedReturnType.isInstance(result)) {
return result;
}
if (QueryExecutionConverters.supports(expectedReturnType)
&& conversionService.canConvert(WRAPPER_TYPE, returnTypeDesciptor)
&& !conversionService.canBypassConvert(WRAPPER_TYPE, TypeDescriptor.valueOf(expectedReturnType))) {
return conversionService.convert(new NullableWrapper(result), expectedReturnType);
}
if (result == null) {
return null;
}
return conversionService.canConvert(result.getClass(), expectedReturnType) ? conversionService.convert(result,
expectedReturnType) : result;
}
}

View File

@@ -35,8 +35,6 @@ import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.core.GenericTypeResolver;
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.Repository;
import org.springframework.data.repository.core.EntityInformation;
import org.springframework.data.repository.core.NamedQueries;
@@ -49,8 +47,6 @@ import org.springframework.data.repository.query.QueryLookupStrategy.Key;
import org.springframework.data.repository.query.QueryMethod;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.data.repository.util.ClassUtils;
import org.springframework.data.repository.util.NullableWrapper;
import org.springframework.data.repository.util.QueryExecutionConverters;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
@@ -63,7 +59,6 @@ import org.springframework.util.ObjectUtils;
*/
public abstract class RepositoryFactorySupport implements BeanClassLoaderAware {
private static final TypeDescriptor WRAPPER_TYPE = TypeDescriptor.valueOf(NullableWrapper.class);
private static final boolean IS_JAVA_8 = org.springframework.util.ClassUtils.isPresent("java.util.Optional",
RepositoryFactorySupport.class.getClassLoader());
@@ -316,7 +311,7 @@ public abstract class RepositoryFactorySupport implements BeanClassLoaderAware {
private final Object customImplementation;
private final RepositoryInformation repositoryInformation;
private final GenericConversionService conversionService;
private final QueryExecutionResultHandler resultHandler;
private final Object target;
/**
@@ -329,10 +324,7 @@ public abstract class RepositoryFactorySupport implements BeanClassLoaderAware {
Assert.notNull(repositoryInformation, "RepositoryInformation must not be null!");
Assert.notNull(target, "Target must not be null!");
DefaultConversionService conversionService = new DefaultConversionService();
QueryExecutionConverters.registerConvertersIn(conversionService);
this.conversionService = conversionService;
this.resultHandler = new QueryExecutionResultHandler();
this.repositoryInformation = repositoryInformation;
this.customImplementation = customImplementation;
this.target = target;
@@ -380,30 +372,12 @@ public abstract class RepositoryFactorySupport implements BeanClassLoaderAware {
Object result = doInvoke(invocation);
Method method = invocation.getMethod();
// 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);
Class<?> expectedReturnType = method.getReturnType();
if (result != null && expectedReturnType.isInstance(result)) {
return result;
}
if (QueryExecutionConverters.supports(expectedReturnType)
&& conversionService.canConvert(WRAPPER_TYPE, methodReturnTypeDescriptor)
&& !conversionService.canBypassConvert(WRAPPER_TYPE, TypeDescriptor.valueOf(expectedReturnType))) {
return conversionService.convert(new NullableWrapper(result), expectedReturnType);
}
if (result == null) {
return null;
}
return conversionService.canConvert(result.getClass(), expectedReturnType) ? conversionService.convert(result,
expectedReturnType) : result;
return resultHandler.postProcessInvocationResult(result, methodReturnTypeDescriptor);
}
private Object doInvoke(MethodInvocation invocation) throws Throwable {