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>
This commit is contained in:
@@ -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;
|
||||
* 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 {
|
||||
}
|
||||
|
||||
@@ -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
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user