Browse Source

Avoid matching multipart parameters annotated with `@ModelAttribute`

The ProxyHandlerMethodArgumentResolver now avoids matching multipart parameters annotated with @ModelAttribute. This allows multipart parameters to be handled by RequestParamMethodArgumentResolver which properly handles multipart arguments.

Also, the `@ProjectedPayload` annotation can now be used on parameters. This prepares for the upcoming removal of support for non-annotated projections.

Fixes #3258
Related tickets #2937
Original pull request: #3277

Signed-off-by: Chris Bono <chris.bono@broadcom.com>
issue/3.5.x/3284
Chris Bono 8 months ago committed by Mark Paluch
parent
commit
39618faf01
No known key found for this signature in database
GPG Key ID: 55BC6374BAA9D973
  1. 10
      src/main/java/org/springframework/data/web/ProjectedPayload.java
  2. 8
      src/main/java/org/springframework/data/web/ProxyingHandlerMethodArgumentResolver.java
  3. 32
      src/test/java/org/springframework/data/web/ProxyingHandlerMethodArgumentResolverUnitTests.java

10
src/main/java/org/springframework/data/web/ProjectedPayload.java

@ -15,11 +15,10 @@ @@ -15,11 +15,10 @@
*/
package org.springframework.data.web;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
@ -27,11 +26,12 @@ import java.lang.annotation.Target; @@ -27,11 +26,12 @@ import java.lang.annotation.Target;
* response payloads to.
*
* @author Oliver Gierke
* @author Chris Bono
* @soundtrack
* @since 1.13
*/
@Documented
@Retention(RUNTIME)
@Target(TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.PARAMETER })
public @interface ProjectedPayload {
}

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

@ -36,11 +36,13 @@ import org.springframework.web.bind.support.WebDataBinderFactory; @@ -36,11 +36,13 @@ import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.annotation.ModelAttributeMethodProcessor;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.multipart.support.MultipartResolutionDelegate;
/**
* {@link HandlerMethodArgumentResolver} to create Proxy instances for interface based controller method parameters.
*
* @author Oliver Gierke
* @author Chris Bono
* @since 1.10
*/
public class ProxyingHandlerMethodArgumentResolver extends ModelAttributeMethodProcessor
@ -88,9 +90,9 @@ public class ProxyingHandlerMethodArgumentResolver extends ModelAttributeMethodP @@ -88,9 +90,9 @@ public class ProxyingHandlerMethodArgumentResolver extends ModelAttributeMethodP
return false;
}
// Annotated parameter
if (parameter.getParameterAnnotation(ProjectedPayload.class) != null
|| parameter.getParameterAnnotation(ModelAttribute.class) != null) {
// Annotated parameter (excluding multipart)
if ((parameter.hasParameterAnnotation(ProjectedPayload.class) || parameter.hasParameterAnnotation(
ModelAttribute.class)) && !MultipartResolutionDelegate.isMultipartArgument(parameter)) {
return true;
}

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

@ -27,11 +27,13 @@ import org.springframework.core.MethodParameter; @@ -27,11 +27,13 @@ import org.springframework.core.MethodParameter;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.multipart.MultipartFile;
/**
* Unit tests for {@link ProxyingHandlerMethodArgumentResolver}.
*
* @author Oliver Gierke
* @author Chris Bono
* @soundtrack Karlijn Langendijk & Sönke Meinen - Englishman In New York (Sting,
* https://www.youtube.com/watch?v=O7LZsqrnaaA)
*/
@ -88,6 +90,30 @@ class ProxyingHandlerMethodArgumentResolverUnitTests { @@ -88,6 +90,30 @@ class ProxyingHandlerMethodArgumentResolverUnitTests {
assertThat(resolver.supportsParameter(parameter)).isTrue();
}
@Test // GH-3258
void doesNotSupportAtModelAttributeForMultipartParam() throws Exception {
var parameter = getParameter("withModelAttributeMultipart", MultipartFile.class);
assertThat(resolver.supportsParameter(parameter)).isFalse();
}
@Test // GH-3258
void doesSupportAtProjectedPayload() throws Exception {
var parameter = getParameter("withProjectedPayload", SampleInterface.class);
assertThat(resolver.supportsParameter(parameter)).isTrue();
}
@Test // GH-3258
void doesNotSupportAtProjectedPayloadForMultipartParam() throws Exception {
var parameter = getParameter("withProjectedPayloadMultipart", MultipartFile.class);
assertThat(resolver.supportsParameter(parameter)).isFalse();
}
private static MethodParameter getParameter(String methodName, Class<?> parameterType) {
var method = ReflectionUtils.findMethod(Controller.class, methodName, parameterType);
@ -112,5 +138,11 @@ class ProxyingHandlerMethodArgumentResolverUnitTests { @@ -112,5 +138,11 @@ class ProxyingHandlerMethodArgumentResolverUnitTests {
void withForeignAnnotation(@Autowired SampleInterface param);
void withModelAttribute(@ModelAttribute SampleInterface param);
void withModelAttributeMultipart(@ModelAttribute MultipartFile file);
void withProjectedPayload(@ProjectedPayload SampleInterface param);
void withProjectedPayloadMultipart(@ProjectedPayload MultipartFile file);
}
}

Loading…
Cancel
Save