Skip to content

Commit 5cae5cb

Browse files
onobcmp911de
authored andcommitted
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 <[email protected]>
1 parent 3afecd5 commit 5cae5cb

File tree

3 files changed

+42
-8
lines changed

3 files changed

+42
-8
lines changed

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,23 @@
1515
*/
1616
package org.springframework.data.web;
1717

18-
import static java.lang.annotation.ElementType.*;
19-
import static java.lang.annotation.RetentionPolicy.*;
20-
2118
import java.lang.annotation.Documented;
19+
import java.lang.annotation.ElementType;
2220
import java.lang.annotation.Retention;
21+
import java.lang.annotation.RetentionPolicy;
2322
import java.lang.annotation.Target;
2423

2524
/**
2625
* Annotation to mark projection interfaces that are supposed to be used as projection interface to bind request or
2726
* response payloads to.
2827
*
2928
* @author Oliver Gierke
29+
* @author Chris Bono
3030
* @soundtrack
3131
* @since 1.13
3232
*/
3333
@Documented
34-
@Retention(RUNTIME)
35-
@Target(TYPE)
34+
@Retention(RetentionPolicy.RUNTIME)
35+
@Target({ ElementType.TYPE, ElementType.PARAMETER })
3636
public @interface ProjectedPayload {
3737
}

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,13 @@
3636
import org.springframework.web.context.request.NativeWebRequest;
3737
import org.springframework.web.method.annotation.ModelAttributeMethodProcessor;
3838
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
39+
import org.springframework.web.multipart.support.MultipartResolutionDelegate;
3940

4041
/**
4142
* {@link HandlerMethodArgumentResolver} to create Proxy instances for interface based controller method parameters.
4243
*
4344
* @author Oliver Gierke
45+
* @author Chris Bono
4446
* @since 1.10
4547
*/
4648
public class ProxyingHandlerMethodArgumentResolver extends ModelAttributeMethodProcessor
@@ -88,9 +90,9 @@ public boolean supportsParameter(MethodParameter parameter) {
8890
return false;
8991
}
9092

91-
// Annotated parameter
92-
if (parameter.getParameterAnnotation(ProjectedPayload.class) != null
93-
|| parameter.getParameterAnnotation(ModelAttribute.class) != null) {
93+
// Annotated parameter (excluding multipart)
94+
if ((parameter.hasParameterAnnotation(ProjectedPayload.class) || parameter.hasParameterAnnotation(
95+
ModelAttribute.class)) && !MultipartResolutionDelegate.isMultipartArgument(parameter)) {
9496
return true;
9597
}
9698

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,13 @@
2727
import org.springframework.core.convert.support.DefaultConversionService;
2828
import org.springframework.util.ReflectionUtils;
2929
import org.springframework.web.bind.annotation.ModelAttribute;
30+
import org.springframework.web.multipart.MultipartFile;
3031

3132
/**
3233
* Unit tests for {@link ProxyingHandlerMethodArgumentResolver}.
3334
*
3435
* @author Oliver Gierke
36+
* @author Chris Bono
3537
* @soundtrack Karlijn Langendijk & Sönke Meinen - Englishman In New York (Sting,
3638
* https://www.youtube.com/watch?v=O7LZsqrnaaA)
3739
*/
@@ -88,6 +90,30 @@ void doesSupportAtModelAttribute() throws Exception {
8890
assertThat(resolver.supportsParameter(parameter)).isTrue();
8991
}
9092

93+
@Test // GH-3258
94+
void doesNotSupportAtModelAttributeForMultipartParam() throws Exception {
95+
96+
var parameter = getParameter("withModelAttributeMultipart", MultipartFile.class);
97+
98+
assertThat(resolver.supportsParameter(parameter)).isFalse();
99+
}
100+
101+
@Test // GH-3258
102+
void doesSupportAtProjectedPayload() throws Exception {
103+
104+
var parameter = getParameter("withProjectedPayload", SampleInterface.class);
105+
106+
assertThat(resolver.supportsParameter(parameter)).isTrue();
107+
}
108+
109+
@Test // GH-3258
110+
void doesNotSupportAtProjectedPayloadForMultipartParam() throws Exception {
111+
112+
var parameter = getParameter("withProjectedPayloadMultipart", MultipartFile.class);
113+
114+
assertThat(resolver.supportsParameter(parameter)).isFalse();
115+
}
116+
91117
private static MethodParameter getParameter(String methodName, Class<?> parameterType) {
92118

93119
var method = ReflectionUtils.findMethod(Controller.class, methodName, parameterType);
@@ -112,5 +138,11 @@ interface Controller {
112138
void withForeignAnnotation(@Autowired SampleInterface param);
113139

114140
void withModelAttribute(@ModelAttribute SampleInterface param);
141+
142+
void withModelAttributeMultipart(@ModelAttribute MultipartFile file);
143+
144+
void withProjectedPayload(@ProjectedPayload SampleInterface param);
145+
146+
void withProjectedPayloadMultipart(@ProjectedPayload MultipartFile file);
115147
}
116148
}

0 commit comments

Comments
 (0)