DATACMNS-1524 - Fix performance regression in QueryExecutionResultHandler.

A side effect of the fix for DATACMNS-1482 trigged source objects that already perfectly match the desired return type would still be subject to detailed inspection of potential conversions, which – by definition – will not kick in.

The code has now been changed to only trigger detailed inspection for collection values.

Related tickets: DATACMNS-1482.
This commit is contained in:
Oliver Drotbohm
2019-07-02 14:25:08 +02:00
parent 736d147446
commit d29fefca5b

View File

@@ -16,11 +16,13 @@
package org.springframework.data.repository.core.support;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import org.springframework.core.CollectionFactory;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.convert.support.GenericConversionService;
@@ -64,6 +66,10 @@ class QueryExecutionResultHandler {
@Nullable
public Object postProcessInvocationResult(@Nullable Object result, Method method) {
if (!processingRequired(result, method.getReturnType())) {
return result;
}
MethodParameter parameter = new MethodParameter(method, -1);
return postProcessInvocationResult(result, 0, parameter);
@@ -96,19 +102,17 @@ class QueryExecutionResultHandler {
// For a wrapper type, try nested resolution first
result = postProcessInvocationResult(result, nestingLevel + 1, parameter);
TypeDescriptor targetType = TypeDescriptor.valueOf(expectedReturnType);
if (conversionService.canConvert(WRAPPER_TYPE, returnTypeDescriptor)
&& !conversionService.canBypassConvert(WRAPPER_TYPE, targetType)) {
return conversionService.convert(new NullableWrapper(result), expectedReturnType);
if (conversionRequired(WRAPPER_TYPE, returnTypeDescriptor)) {
return conversionService.convert(new NullableWrapper(result), returnTypeDescriptor);
}
if (result != null
&& conversionService.canConvert(TypeDescriptor.valueOf(result.getClass()), returnTypeDescriptor)
&& !conversionService.canBypassConvert(TypeDescriptor.valueOf(result.getClass()), targetType)) {
if (result != null) {
return conversionService.convert(result, expectedReturnType);
TypeDescriptor source = TypeDescriptor.valueOf(result.getClass());
if (conversionRequired(source, returnTypeDescriptor)) {
return conversionService.convert(result, returnTypeDescriptor);
}
}
}
@@ -128,6 +132,20 @@ class QueryExecutionResultHandler {
: null;
}
/**
* Returns whether the configured {@link ConversionService} can convert between the given {@link TypeDescriptor}s and
* the conversion will not be a no-op.
*
* @param source
* @param target
* @return
*/
private boolean conversionRequired(TypeDescriptor source, TypeDescriptor target) {
return conversionService.canConvert(source, target) //
&& !conversionService.canBypassConvert(source, target);
}
/**
* Unwraps the given value if it's a JDK 8 {@link Optional}.
*
@@ -142,6 +160,22 @@ class QueryExecutionResultHandler {
return null;
}
return Optional.class.isInstance(source) ? Optional.class.cast(source).orElse(null) : source;
return Optional.class.isInstance(source) //
? Optional.class.cast(source).orElse(null) //
: source;
}
/**
* Returns whether we have to process the given source object in the first place.
*
* @param source can be {@literal null}.
* @param targetType must not be {@literal null}.
* @return
*/
private static boolean processingRequired(@Nullable Object source, Class<?> targetType) {
return !targetType.isInstance(source) //
|| source == null //
|| Collection.class.isInstance(source);
}
}