Throw UnsupportedOperationException when a projected value cannot be returned.
We now throw UnsupportedOperationException when a projected value cannot be returned because it cannot be brought into the target type, either via conversion or projection. This exception improves the error message by avoiding throwing IllegalArgumentException: Projection type must be an interface from the last branch that falls back into projections. Closes #2290. Original Pull Request: #2291
This commit is contained in:
committed by
Christoph Strobl
parent
5e702a8c8a
commit
cdeecd4a75
@@ -104,8 +104,14 @@ class ProjectingMethodInterceptor implements MethodInterceptor {
|
||||
return projectMapValues((Map<?, ?>) result, type);
|
||||
} else if (conversionRequiredAndPossible(result, type.getType())) {
|
||||
return conversionService.convert(result, type.getType());
|
||||
} else {
|
||||
} else if (ClassUtils.isAssignable(type.getType(), result.getClass())) {
|
||||
return result;
|
||||
} else if (type.getType().isInterface()) {
|
||||
return getProjection(result, type.getType());
|
||||
} else {
|
||||
throw new UnsupportedOperationException(String.format(
|
||||
"Cannot convert value '%s' of type '%s' to '%s' and cannot create a projection as the target type is not an interface",
|
||||
result, ClassUtils.getDescriptiveType(result), ClassUtils.getQualifiedName(type.getType())));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,7 +161,7 @@ class ProjectingMethodInterceptor implements MethodInterceptor {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Object getProjection(Object result, Class<?> returnType) {
|
||||
private Object getProjection(@Nullable Object result, Class<?> returnType) {
|
||||
return result == null || ClassUtils.isAssignable(returnType, result.getClass()) ? result
|
||||
: factory.createProjection(returnType, result);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import static org.assertj.core.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
@@ -95,6 +96,21 @@ class ProjectingMethodInterceptorUnitTests {
|
||||
verify(factory, times(0)).createProjection((Class<?>) any(), any());
|
||||
}
|
||||
|
||||
@Test // #2290
|
||||
void failsForNonConvertibleTypes() throws Throwable {
|
||||
|
||||
MethodInterceptor methodInterceptor = new ProjectingMethodInterceptor(factory, interceptor, conversionService);
|
||||
|
||||
when(invocation.getMethod()).thenReturn(Helper.class.getMethod("getBoolean"));
|
||||
when(interceptor.invoke(invocation)).thenReturn(BigInteger.valueOf(1));
|
||||
|
||||
assertThatThrownBy(() -> methodInterceptor.invoke(invocation)) //
|
||||
.isInstanceOf(UnsupportedOperationException.class) //
|
||||
.hasMessageContaining("'1'") //
|
||||
.hasMessageContaining("BigInteger") //
|
||||
.hasMessageContaining("boolean");
|
||||
}
|
||||
|
||||
@Test // DATAREST-394, DATAREST-408
|
||||
@SuppressWarnings("unchecked")
|
||||
void appliesProjectionToNonEmptySets() throws Throwable {
|
||||
@@ -213,6 +229,8 @@ class ProjectingMethodInterceptorUnitTests {
|
||||
|
||||
long getPrimitive();
|
||||
|
||||
boolean getBoolean();
|
||||
|
||||
Collection<HelperProjection> getHelperCollection();
|
||||
|
||||
List<HelperProjection> getHelperList();
|
||||
|
||||
Reference in New Issue
Block a user