diff --git a/spring-web/src/main/java/org/springframework/web/bind/annotation/RequestMappingReflectiveProcessor.java b/spring-web/src/main/java/org/springframework/web/bind/annotation/RequestMappingReflectiveProcessor.java index a39ae5b0ba..c1661d39f6 100644 --- a/spring-web/src/main/java/org/springframework/web/bind/annotation/RequestMappingReflectiveProcessor.java +++ b/spring-web/src/main/java/org/springframework/web/bind/annotation/RequestMappingReflectiveProcessor.java @@ -72,7 +72,8 @@ class RequestMappingReflectiveProcessor implements ReflectiveProcessor { hints.registerMethod(method, hint -> hint.setModes(ExecutableMode.INVOKE)); for (Parameter parameter : method.getParameters()) { MethodParameter methodParameter = MethodParameter.forParameter(parameter); - if (methodParameter.hasParameterAnnotation(RequestBody.class)) { + if (methodParameter.hasParameterAnnotation(RequestBody.class) || + methodParameter.hasParameterAnnotation(ModelAttribute.class)) { this.bindingRegistrar.registerReflectionHints(hints, methodParameter.getGenericParameterType()); } else if (HttpEntity.class.isAssignableFrom(methodParameter.getParameterType())) { diff --git a/spring-web/src/test/java/org/springframework/web/bind/annotation/RequestMappingReflectiveProcessorTests.java b/spring-web/src/test/java/org/springframework/web/bind/annotation/RequestMappingReflectiveProcessorTests.java index c97d3aadd3..ce37f5ed69 100644 --- a/spring-web/src/test/java/org/springframework/web/bind/annotation/RequestMappingReflectiveProcessorTests.java +++ b/spring-web/src/test/java/org/springframework/web/bind/annotation/RequestMappingReflectiveProcessorTests.java @@ -74,6 +74,24 @@ public class RequestMappingReflectiveProcessorTests { typeHint -> assertThat(typeHint.getType()).isEqualTo(TypeReference.of(String.class))); } + @Test + void registerReflectiveHintsForMethodWithModelAttribute() throws NoSuchMethodException { + Method method = SampleController.class.getDeclaredMethod("postForm", Request.class); + processor.registerReflectionHints(hints, method); + assertThat(hints.typeHints()).satisfiesExactlyInAnyOrder( + typeHint -> assertThat(typeHint.getType()).isEqualTo(TypeReference.of(SampleController.class)), + typeHint -> { + assertThat(typeHint.getType()).isEqualTo(TypeReference.of(Request.class)); + assertThat(typeHint.getMemberCategories()).containsExactlyInAnyOrder( + MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, + MemberCategory.DECLARED_FIELDS); + assertThat(typeHint.methods()).satisfiesExactlyInAnyOrder( + hint -> assertThat(hint.getName()).isEqualTo("getMessage"), + hint -> assertThat(hint.getName()).isEqualTo("setMessage")); + }, + typeHint -> assertThat(typeHint.getType()).isEqualTo(TypeReference.of(String.class))); + } + @Test void registerReflectiveHintsForMethodWithRestController() throws NoSuchMethodException { Method method = SampleRestController.class.getDeclaredMethod("get"); @@ -177,6 +195,10 @@ public class RequestMappingReflectiveProcessorTests { void post(@RequestBody Request request) { } + @PostMapping + void postForm(@ModelAttribute Request request) { + } + @GetMapping @ResponseBody String message() {