Browse Source

ProxyHandlerMethodArgumentResolver now avoids matching parameters annotated with Spring annotation.

We now explicitly do not match handler method parameters that are annotated with anything but @ModelAttribute or @ProjectedPayload. This prevents us accidentally opting into parameter handling for annotated parameters that use interfaces for their declaration and are supposed to be handled by some other infrastructure.

Fixes GH-2937.
3.2.x
Oliver Drotbohm 1 year ago
parent
commit
b7a9c75a32
  1. 14
      src/main/java/org/springframework/data/web/ProxyingHandlerMethodArgumentResolver.java
  2. 3
      src/test/java/example/SampleInterface.java
  3. 32
      src/test/java/org/springframework/data/web/ProxyingHandlerMethodArgumentResolverUnitTests.java

14
src/main/java/org/springframework/data/web/ProxyingHandlerMethodArgumentResolver.java

@ -15,6 +15,7 @@
*/ */
package org.springframework.data.web; package org.springframework.data.web;
import java.lang.annotation.Annotation;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@ -30,6 +31,7 @@ import org.springframework.core.convert.ConversionService;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory; import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.annotation.ModelAttributeMethodProcessor; import org.springframework.web.method.annotation.ModelAttributeMethodProcessor;
@ -87,7 +89,8 @@ public class ProxyingHandlerMethodArgumentResolver extends ModelAttributeMethodP
} }
// Annotated parameter // Annotated parameter
if (parameter.getParameterAnnotation(ProjectedPayload.class) != null) { if (parameter.getParameterAnnotation(ProjectedPayload.class) != null
|| parameter.getParameterAnnotation(ModelAttribute.class) != null) {
return true; return true;
} }
@ -96,6 +99,15 @@ public class ProxyingHandlerMethodArgumentResolver extends ModelAttributeMethodP
return true; return true;
} }
// Exclude parameters annotated with Spring annotation
if (Arrays.stream(parameter.getParameterAnnotations())
.map(Annotation::annotationType)
.map(Class::getPackageName)
.anyMatch(it -> it.startsWith("org.springframework"))) {
return false;
}
// Fallback for only user defined interfaces // Fallback for only user defined interfaces
String packageName = ClassUtils.getPackageName(type); String packageName = ClassUtils.getPackageName(type);

3
src/test/java/SampleInterface.java → src/test/java/example/SampleInterface.java

@ -18,4 +18,7 @@
* @author Oliver Gierke * @author Oliver Gierke
* @see org.springframework.data.web.ProxyingHandlerMethodArgumentResolverUnitTests * @see org.springframework.data.web.ProxyingHandlerMethodArgumentResolverUnitTests
*/ */
package example;
public interface SampleInterface {} public interface SampleInterface {}

32
src/test/java/org/springframework/data/web/ProxyingHandlerMethodArgumentResolverUnitTests.java

@ -17,12 +17,16 @@ package org.springframework.data.web;
import static org.assertj.core.api.Assertions.*; import static org.assertj.core.api.Assertions.*;
import example.SampleInterface;
import java.util.List; import java.util.List;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter; import org.springframework.core.MethodParameter;
import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.data.web.ProjectingJackson2HttpMessageConverterUnitTests.SampleInterface; import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.ModelAttribute;
/** /**
* Unit tests for {@link ProxyingHandlerMethodArgumentResolver}. * Unit tests for {@link ProxyingHandlerMethodArgumentResolver}.
@ -72,6 +76,28 @@ public class ProxyingHandlerMethodArgumentResolverUnitTests {
assertThat(resolver.supportsParameter(parameter)).isFalse(); assertThat(resolver.supportsParameter(parameter)).isFalse();
} }
@Test // GH-2937
void doesNotSupportForeignSpringAnnotations() throws Exception {
var parameter = getParameter("withForeignAnnotation", SampleInterface.class);
assertThat(resolver.supportsParameter(parameter)).isFalse();
}
@Test // GH-2937
void doesSupportAtModelAttribute() throws Exception {
var parameter = getParameter("withModelAttribute", SampleInterface.class);
assertThat(resolver.supportsParameter(parameter)).isTrue();
}
private static MethodParameter getParameter(String methodName, Class<?> parameterType) {
var method = ReflectionUtils.findMethod(Controller.class, methodName, parameterType);
return new MethodParameter(method, 0);
}
@ProjectedPayload @ProjectedPayload
interface AnnotatedInterface {} interface AnnotatedInterface {}
@ -86,5 +112,9 @@ public class ProxyingHandlerMethodArgumentResolverUnitTests {
void with(SampleInterface param); void with(SampleInterface param);
void with(List<Object> param); void with(List<Object> param);
void withForeignAnnotation(@Autowired SampleInterface param);
void withModelAttribute(@ModelAttribute SampleInterface param);
} }
} }

Loading…
Cancel
Save