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/ControllerMappingReflectiveProcessor.java
similarity index 59%
rename from spring-web/src/main/java/org/springframework/web/bind/annotation/RequestMappingReflectiveProcessor.java
rename to spring-web/src/main/java/org/springframework/web/bind/annotation/ControllerMappingReflectiveProcessor.java
index d2b03f12c17..878f3af049e 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/ControllerMappingReflectiveProcessor.java
@@ -29,11 +29,12 @@ import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.http.HttpEntity;
import org.springframework.lang.Nullable;
+import org.springframework.stereotype.Controller;
/**
- * {@link ReflectiveProcessor} implementation for {@link RequestMapping}
- * annotated types. On top of registering reflection hints for invoking
- * the annotated method, this implementation handles:
+ * {@link ReflectiveProcessor} implementation for {@link Controller} and
+ * controller-specific annotated methods. On top of registering reflection
+ * hints for invoking the annotated method, this implementation handles:
*
* - Return types annotated with {@link ResponseBody}.
* - Parameters annotated with {@link RequestBody}.
@@ -44,7 +45,7 @@ import org.springframework.lang.Nullable;
* @author Sebastien Deleuze
* @since 6.0
*/
-class RequestMappingReflectiveProcessor implements ReflectiveProcessor {
+class ControllerMappingReflectiveProcessor implements ReflectiveProcessor {
private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();
@@ -58,45 +59,47 @@ class RequestMappingReflectiveProcessor implements ReflectiveProcessor {
}
}
+ protected final BindingReflectionHintsRegistrar getBindingRegistrar() {
+ return this.bindingRegistrar;
+ }
+
protected void registerTypeHints(ReflectionHints hints, Class> type) {
hints.registerType(type);
}
protected void registerMethodHints(ReflectionHints hints, Method method) {
- hints.registerMethod(method, ExecutableMode.INVOKE);
- registerParameterHints(hints, method);
- registerReturnValueHints(hints, method);
- }
-
- protected void registerParameterHints(ReflectionHints hints, Method method) {
hints.registerMethod(method, ExecutableMode.INVOKE);
for (Parameter parameter : method.getParameters()) {
- MethodParameter methodParameter = MethodParameter.forParameter(parameter);
- if (methodParameter.hasParameterAnnotation(RequestBody.class) ||
- methodParameter.hasParameterAnnotation(ModelAttribute.class)) {
- this.bindingRegistrar.registerReflectionHints(hints, methodParameter.getGenericParameterType());
- }
- else if (HttpEntity.class.isAssignableFrom(methodParameter.getParameterType())) {
- this.bindingRegistrar.registerReflectionHints(hints, getHttpEntityType(methodParameter));
- }
+ registerParameterTypeHints(hints, MethodParameter.forParameter(parameter));
+ }
+ registerReturnTypeHints(hints, MethodParameter.forExecutable(method, -1));
+ }
+
+ protected void registerParameterTypeHints(ReflectionHints hints, MethodParameter methodParameter) {
+ if (methodParameter.hasParameterAnnotation(RequestBody.class) ||
+ methodParameter.hasParameterAnnotation(ModelAttribute.class)) {
+ this.bindingRegistrar.registerReflectionHints(hints, methodParameter.getGenericParameterType());
+ }
+ else if (HttpEntity.class.isAssignableFrom(methodParameter.getParameterType())) {
+ this.bindingRegistrar.registerReflectionHints(hints, getHttpEntityType(methodParameter));
}
}
- protected void registerReturnValueHints(ReflectionHints hints, Method method) {
- MethodParameter returnType = MethodParameter.forExecutable(method, -1);
- if (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
- returnType.hasMethodAnnotation(ResponseBody.class)) {
- this.bindingRegistrar.registerReflectionHints(hints, returnType.getGenericParameterType());
+ protected void registerReturnTypeHints(ReflectionHints hints, MethodParameter returnTypeParameter) {
+ if (AnnotatedElementUtils.hasAnnotation(returnTypeParameter.getContainingClass(), ResponseBody.class) ||
+ returnTypeParameter.hasMethodAnnotation(ResponseBody.class)) {
+ this.bindingRegistrar.registerReflectionHints(hints, returnTypeParameter.getGenericParameterType());
}
- else if (HttpEntity.class.isAssignableFrom(returnType.getParameterType())) {
- this.bindingRegistrar.registerReflectionHints(hints, getHttpEntityType(returnType));
+ else if (HttpEntity.class.isAssignableFrom(returnTypeParameter.getParameterType())) {
+ this.bindingRegistrar.registerReflectionHints(hints, getHttpEntityType(returnTypeParameter));
}
}
@Nullable
- protected Type getHttpEntityType(MethodParameter parameter) {
+ private Type getHttpEntityType(MethodParameter parameter) {
MethodParameter nestedParameter = parameter.nested();
- return (nestedParameter.getNestedParameterType() == nestedParameter.getParameterType() ? null : nestedParameter.getNestedParameterType());
+ return (nestedParameter.getNestedParameterType() == nestedParameter.getParameterType()
+ ? null : nestedParameter.getNestedParameterType());
}
}
diff --git a/spring-web/src/main/java/org/springframework/web/bind/annotation/ExceptionHandler.java b/spring-web/src/main/java/org/springframework/web/bind/annotation/ExceptionHandler.java
index 4f0ee2ad788..bb80146627c 100644
--- a/spring-web/src/main/java/org/springframework/web/bind/annotation/ExceptionHandler.java
+++ b/spring-web/src/main/java/org/springframework/web/bind/annotation/ExceptionHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2021 the original author or authors.
+ * Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,6 +22,8 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+import org.springframework.aot.hint.annotation.Reflective;
+
/**
* Annotation for handling exceptions in specific handler classes and/or
* handler methods.
@@ -106,6 +108,7 @@ import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
+@Reflective(ExceptionHandlerReflectiveProcessor.class)
public @interface ExceptionHandler {
/**
diff --git a/spring-web/src/main/java/org/springframework/web/bind/annotation/ExceptionHandlerReflectiveProcessor.java b/spring-web/src/main/java/org/springframework/web/bind/annotation/ExceptionHandlerReflectiveProcessor.java
new file mode 100644
index 00000000000..448392ea759
--- /dev/null
+++ b/spring-web/src/main/java/org/springframework/web/bind/annotation/ExceptionHandlerReflectiveProcessor.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2002-2022 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.web.bind.annotation;
+
+import org.springframework.aot.hint.ReflectionHints;
+import org.springframework.core.MethodParameter;
+import org.springframework.http.ProblemDetail;
+
+/**
+ * {@link ControllerMappingReflectiveProcessor} specific implementation that
+ * handles {@link ExceptionHandler @ExceptionHandler}-specific types.
+ *
+ * @author Stephane Nicoll
+ * @since 6.0
+ */
+class ExceptionHandlerReflectiveProcessor extends ControllerMappingReflectiveProcessor{
+
+ @Override
+ protected void registerReturnTypeHints(ReflectionHints hints, MethodParameter returnTypeParameter) {
+ Class> returnType = returnTypeParameter.getParameterType();
+ if (ProblemDetail.class.isAssignableFrom(returnType)) {
+ getBindingRegistrar().registerReflectionHints(hints, returnTypeParameter.getGenericParameterType());
+ }
+ super.registerReturnTypeHints(hints, returnTypeParameter);
+ }
+}
diff --git a/spring-web/src/main/java/org/springframework/web/bind/annotation/RequestMapping.java b/spring-web/src/main/java/org/springframework/web/bind/annotation/RequestMapping.java
index 65d7ceb6682..9a677fa13fe 100644
--- a/spring-web/src/main/java/org/springframework/web/bind/annotation/RequestMapping.java
+++ b/spring-web/src/main/java/org/springframework/web/bind/annotation/RequestMapping.java
@@ -73,7 +73,7 @@ import org.springframework.core.annotation.AliasFor;
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
-@Reflective(RequestMappingReflectiveProcessor.class)
+@Reflective(ControllerMappingReflectiveProcessor.class)
public @interface RequestMapping {
/**
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/ControllerMappingReflectiveProcessorTests.java
similarity index 97%
rename from spring-web/src/test/java/org/springframework/web/bind/annotation/RequestMappingReflectiveProcessorTests.java
rename to spring-web/src/test/java/org/springframework/web/bind/annotation/ControllerMappingReflectiveProcessorTests.java
index ce37f5ed694..8f68f9bc0dc 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/ControllerMappingReflectiveProcessorTests.java
@@ -28,13 +28,13 @@ import org.springframework.http.HttpEntity;
import static org.assertj.core.api.Assertions.assertThat;
/**
- * Tests for {@link RequestMappingReflectiveProcessor}.
+ * Tests for {@link ControllerMappingReflectiveProcessor}.
*
* @author Sebastien Deleuze
*/
-public class RequestMappingReflectiveProcessorTests {
+public class ControllerMappingReflectiveProcessorTests {
- private final RequestMappingReflectiveProcessor processor = new RequestMappingReflectiveProcessor();
+ private final ControllerMappingReflectiveProcessor processor = new ControllerMappingReflectiveProcessor();
private final ReflectionHints hints = new ReflectionHints();