Skip to content

Commit e3a8edf

Browse files
Avoid leaking data via Exception message.
Do not include the result value in the exception message to avoid data exposure. Improve data flow to avoid superfluous null checks. See #2290. Original Pull Request: #2291.
1 parent cdeecd4 commit e3a8edf

File tree

2 files changed

+14
-29
lines changed

2 files changed

+14
-29
lines changed

src/main/java/org/springframework/data/projection/ProjectingMethodInterceptor.java

+12-27
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727

2828
import org.aopalliance.intercept.MethodInterceptor;
2929
import org.aopalliance.intercept.MethodInvocation;
30-
3130
import org.springframework.core.CollectionFactory;
3231
import org.springframework.core.convert.ConversionService;
3332
import org.springframework.data.util.ClassTypeInformation;
@@ -45,6 +44,7 @@
4544
*
4645
* @author Oliver Gierke
4746
* @author Mark Paluch
47+
* @author Christoph Strobl
4848
* @since 1.10
4949
*/
5050
class ProjectingMethodInterceptor implements MethodInterceptor {
@@ -98,20 +98,22 @@ protected Object potentiallyConvertResult(TypeInformation<?> type, @Nullable Obj
9898
return null;
9999
}
100100

101-
if (type.isCollectionLike() && !ClassUtils.isPrimitiveArray(type.getType())) {
101+
Class<?> targetType = type.getType();
102+
103+
if (type.isCollectionLike() && !ClassUtils.isPrimitiveArray(targetType)) {
102104
return projectCollectionElements(asCollection(result), type);
103105
} else if (type.isMap()) {
104106
return projectMapValues((Map<?, ?>) result, type);
105-
} else if (conversionRequiredAndPossible(result, type.getType())) {
106-
return conversionService.convert(result, type.getType());
107-
} else if (ClassUtils.isAssignable(type.getType(), result.getClass())) {
107+
} else if (ClassUtils.isAssignable(targetType, result.getClass())) {
108108
return result;
109-
} else if (type.getType().isInterface()) {
110-
return getProjection(result, type.getType());
109+
} else if (conversionService.canConvert(result.getClass(), targetType)) {
110+
return conversionService.convert(result, targetType);
111+
} else if (targetType.isInterface()) {
112+
return getProjection(result, targetType);
111113
} else {
112-
throw new UnsupportedOperationException(String.format(
113-
"Cannot convert value '%s' of type '%s' to '%s' and cannot create a projection as the target type is not an interface",
114-
result, ClassUtils.getDescriptiveType(result), ClassUtils.getQualifiedName(type.getType())));
114+
throw new UnsupportedOperationException(
115+
String.format("Cannot project %s to %s. Target type is not an interface and no matching Converter found!",
116+
ClassUtils.getDescriptiveType(result), ClassUtils.getQualifiedName(targetType)));
115117
}
116118
}
117119

@@ -166,23 +168,6 @@ private Object getProjection(@Nullable Object result, Class<?> returnType) {
166168
: factory.createProjection(returnType, result);
167169
}
168170

169-
/**
170-
* Returns whether the source object needs to be converted to the given target type and whether we can convert it at
171-
* all.
172-
*
173-
* @param source can be {@literal null}.
174-
* @param targetType must not be {@literal null}.
175-
* @return
176-
*/
177-
private boolean conversionRequiredAndPossible(Object source, Class<?> targetType) {
178-
179-
if (source == null || targetType.isInstance(source)) {
180-
return false;
181-
}
182-
183-
return conversionService.canConvert(source.getClass(), targetType);
184-
}
185-
186171
/**
187172
* Turns the given value into a {@link Collection}. Will turn an array into a collection an wrap all other values into
188173
* a single-element collection.

src/test/java/org/springframework/data/projection/ProjectingMethodInterceptorUnitTests.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
* @author Oliver Gierke
4444
* @author Saulo Medeiros de Araujo
4545
* @author Mark Paluch
46+
* @author Christoph Strobl
4647
*/
4748
@ExtendWith(MockitoExtension.class)
4849
class ProjectingMethodInterceptorUnitTests {
@@ -96,7 +97,7 @@ void considersPrimitivesAsWrappers() throws Throwable {
9697
verify(factory, times(0)).createProjection((Class<?>) any(), any());
9798
}
9899

99-
@Test // #2290
100+
@Test // GH-2290
100101
void failsForNonConvertibleTypes() throws Throwable {
101102

102103
MethodInterceptor methodInterceptor = new ProjectingMethodInterceptor(factory, interceptor, conversionService);
@@ -106,7 +107,6 @@ void failsForNonConvertibleTypes() throws Throwable {
106107

107108
assertThatThrownBy(() -> methodInterceptor.invoke(invocation)) //
108109
.isInstanceOf(UnsupportedOperationException.class) //
109-
.hasMessageContaining("'1'") //
110110
.hasMessageContaining("BigInteger") //
111111
.hasMessageContaining("boolean");
112112
}

0 commit comments

Comments
 (0)