diff --git a/spring-web/src/main/java/org/springframework/web/method/ControllerAdviceBean.java b/spring-web/src/main/java/org/springframework/web/method/ControllerAdviceBean.java index b7d1701a375..20e4207c462 100644 --- a/spring-web/src/main/java/org/springframework/web/method/ControllerAdviceBean.java +++ b/spring-web/src/main/java/org/springframework/web/method/ControllerAdviceBean.java @@ -33,7 +33,6 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.OrderComparator; import org.springframework.core.Ordered; -import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.core.annotation.OrderUtils; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -43,10 +42,11 @@ import org.springframework.web.bind.annotation.ControllerAdvice; /** * Encapsulates information about an {@link ControllerAdvice @ControllerAdvice} * Spring-managed bean without necessarily requiring it to be instantiated. + * The {@link #findAnnotatedBeans(ApplicationContext)} method can be used to + * discover such beans. * - *
The {@link #findAnnotatedBeans(ApplicationContext)} method can be used to - * discover such beans. However, a {@code ControllerAdviceBean} may be created - * from any object, including ones without an {@code @ControllerAdvice} annotation. + *
This class is internal to Spring Framework and is not meant to be used
+ * by applications to manually create {@code @ControllerAdvice} beans.
*
* @author Rossen Stoyanchev
* @author Brian Clozel
@@ -56,11 +56,7 @@ import org.springframework.web.bind.annotation.ControllerAdvice;
*/
public class ControllerAdviceBean implements Ordered {
- /**
- * Reference to the actual bean instance or a {@code String} representing
- * the bean name.
- */
- private final Object beanOrName;
+ private final String beanName;
private final boolean isSingleton;
@@ -76,38 +72,12 @@ public class ControllerAdviceBean implements Ordered {
private final HandlerTypePredicate beanTypePredicate;
- @Nullable
private final BeanFactory beanFactory;
@Nullable
private Integer order;
- /**
- * Create a {@code ControllerAdviceBean} using the given bean instance.
- * @param bean the bean instance
- */
- public ControllerAdviceBean(Object bean) {
- Assert.notNull(bean, "Bean must not be null");
- this.beanOrName = bean;
- this.isSingleton = true;
- this.resolvedBean = bean;
- this.beanType = ClassUtils.getUserClass(bean.getClass());
- this.beanTypePredicate = createBeanTypePredicate(this.beanType);
- this.beanFactory = null;
- }
-
- /**
- * Create a {@code ControllerAdviceBean} using the given bean name and
- * {@code BeanFactory}.
- * @param beanName the name of the bean
- * @param beanFactory a {@code BeanFactory} to retrieve the bean type initially
- * and later to resolve the actual bean
- */
- public ControllerAdviceBean(String beanName, BeanFactory beanFactory) {
- this(beanName, beanFactory, null);
- }
-
/**
* Create a {@code ControllerAdviceBean} using the given bean name,
* {@code BeanFactory}, and {@link ControllerAdvice @ControllerAdvice}
@@ -115,21 +85,20 @@ public class ControllerAdviceBean implements Ordered {
* @param beanName the name of the bean
* @param beanFactory a {@code BeanFactory} to retrieve the bean type initially
* and later to resolve the actual bean
- * @param controllerAdvice the {@code @ControllerAdvice} annotation for the
- * bean, or {@code null} if not yet retrieved
+ * @param controllerAdvice the {@code @ControllerAdvice} annotation for the bean
* @since 5.2
*/
- public ControllerAdviceBean(String beanName, BeanFactory beanFactory, @Nullable ControllerAdvice controllerAdvice) {
+ public ControllerAdviceBean(String beanName, BeanFactory beanFactory, ControllerAdvice controllerAdvice) {
Assert.hasText(beanName, "Bean name must contain text");
Assert.notNull(beanFactory, "BeanFactory must not be null");
Assert.isTrue(beanFactory.containsBean(beanName), () -> "BeanFactory [" + beanFactory +
"] does not contain specified controller advice bean '" + beanName + "'");
+ Assert.notNull(controllerAdvice, "ControllerAdvice must not be null");
- this.beanOrName = beanName;
+ this.beanName = beanName;
this.isSingleton = beanFactory.isSingleton(beanName);
this.beanType = getBeanType(beanName, beanFactory);
- this.beanTypePredicate = (controllerAdvice != null ? createBeanTypePredicate(controllerAdvice) :
- createBeanTypePredicate(this.beanType));
+ this.beanTypePredicate = createBeanTypePredicate(controllerAdvice);
this.beanFactory = beanFactory;
}
@@ -158,21 +127,14 @@ public class ControllerAdviceBean implements Ordered {
@Override
public int getOrder() {
if (this.order == null) {
- String beanName = null;
Object resolvedBean = null;
- if (this.beanFactory != null && this.beanOrName instanceof String stringBeanName) {
- beanName = stringBeanName;
- String targetBeanName = ScopedProxyUtils.getTargetBeanName(beanName);
- boolean isScopedProxy = this.beanFactory.containsBean(targetBeanName);
- // Avoid eager @ControllerAdvice bean resolution for scoped proxies,
- // since attempting to do so during context initialization would result
- // in an exception due to the current absence of the scope. For example,
- // an HTTP request or session scope is not active during initialization.
- if (!isScopedProxy && !ScopedProxyUtils.isScopedTarget(beanName)) {
- resolvedBean = resolveBean();
- }
- }
- else {
+ String targetBeanName = ScopedProxyUtils.getTargetBeanName(this.beanName);
+ boolean isScopedProxy = this.beanFactory.containsBean(targetBeanName);
+ // Avoid eager @ControllerAdvice bean resolution for scoped proxies,
+ // since attempting to do so during context initialization would result
+ // in an exception due to the current absence of the scope. For example,
+ // an HTTP request or session scope is not active during initialization.
+ if (!isScopedProxy && !ScopedProxyUtils.isScopedTarget(this.beanName)) {
resolvedBean = resolveBean();
}
@@ -180,9 +142,9 @@ public class ControllerAdviceBean implements Ordered {
this.order = ordered.getOrder();
}
else {
- if (beanName != null && this.beanFactory instanceof ConfigurableBeanFactory cbf) {
+ if (this.beanFactory instanceof ConfigurableBeanFactory cbf) {
try {
- BeanDefinition bd = cbf.getMergedBeanDefinition(beanName);
+ BeanDefinition bd = cbf.getMergedBeanDefinition(this.beanName);
if (bd instanceof RootBeanDefinition rbd) {
Method factoryMethod = rbd.getResolvedFactoryMethod();
if (factoryMethod != null) {
@@ -225,9 +187,7 @@ public class ControllerAdviceBean implements Ordered {
*/
public Object resolveBean() {
if (this.resolvedBean == null) {
- // this.beanOrName must be a String representing the bean name if
- // this.resolvedBean is null.
- Object resolvedBean = obtainBeanFactory().getBean((String) this.beanOrName);
+ Object resolvedBean = this.beanFactory.getBean(this.beanName);
// Don't cache non-singletons (e.g., prototypes).
if (!this.isSingleton) {
return resolvedBean;
@@ -237,11 +197,6 @@ public class ControllerAdviceBean implements Ordered {
return this.resolvedBean;
}
- private BeanFactory obtainBeanFactory() {
- Assert.state(this.beanFactory != null, "No BeanFactory set");
- return this.beanFactory;
- }
-
/**
* Check whether the given bean type should be advised by this
* {@code ControllerAdviceBean}.
@@ -257,17 +212,17 @@ public class ControllerAdviceBean implements Ordered {
@Override
public boolean equals(@Nullable Object other) {
return (this == other || (other instanceof ControllerAdviceBean that &&
- this.beanOrName.equals(that.beanOrName) && this.beanFactory == that.beanFactory));
+ this.beanName.equals(that.beanName) && this.beanFactory == that.beanFactory));
}
@Override
public int hashCode() {
- return this.beanOrName.hashCode();
+ return this.beanName.hashCode();
}
@Override
public String toString() {
- return this.beanOrName.toString();
+ return this.beanName;
}
@@ -308,22 +263,13 @@ public class ControllerAdviceBean implements Ordered {
return (beanType != null ? ClassUtils.getUserClass(beanType) : null);
}
- private static HandlerTypePredicate createBeanTypePredicate(@Nullable Class> beanType) {
- ControllerAdvice controllerAdvice = (beanType != null ?
- AnnotatedElementUtils.findMergedAnnotation(beanType, ControllerAdvice.class) : null);
- return createBeanTypePredicate(controllerAdvice);
- }
-
- private static HandlerTypePredicate createBeanTypePredicate(@Nullable ControllerAdvice controllerAdvice) {
- if (controllerAdvice != null) {
- return HandlerTypePredicate.builder()
- .basePackage(controllerAdvice.basePackages())
- .basePackageClass(controllerAdvice.basePackageClasses())
- .assignableType(controllerAdvice.assignableTypes())
- .annotation(controllerAdvice.annotations())
- .build();
- }
- return HandlerTypePredicate.forAnyHandlerType();
+ private static HandlerTypePredicate createBeanTypePredicate(ControllerAdvice controllerAdvice) {
+ return HandlerTypePredicate.builder()
+ .basePackage(controllerAdvice.basePackages())
+ .basePackageClass(controllerAdvice.basePackageClasses())
+ .assignableType(controllerAdvice.assignableTypes())
+ .annotation(controllerAdvice.annotations())
+ .build();
}
}
diff --git a/spring-web/src/test/java/org/springframework/web/method/ControllerAdviceBeanTests.java b/spring-web/src/test/java/org/springframework/web/method/ControllerAdviceBeanTests.java
index b04f5c22a96..f89bd5366d5 100644
--- a/spring-web/src/test/java/org/springframework/web/method/ControllerAdviceBeanTests.java
+++ b/spring-web/src/test/java/org/springframework/web/method/ControllerAdviceBeanTests.java
@@ -23,22 +23,23 @@ import java.util.List;
import jakarta.annotation.Priority;
import org.junit.jupiter.api.Test;
-import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.context.support.StaticApplicationContext;
import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered;
+import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.Order;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.RestController;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
/**
* Unit and integration tests for {@link ControllerAdviceBean}.
@@ -48,54 +49,52 @@ import static org.mockito.Mockito.verify;
*/
class ControllerAdviceBeanTests {
+ private StaticApplicationContext applicationContext = new StaticApplicationContext();
+
@Test
- void constructorPreconditions() {
+ void shouldFailForNullOrEmptyBeanName() {
assertThatIllegalArgumentException()
- .isThrownBy(() -> new ControllerAdviceBean(null))
- .withMessage("Bean must not be null");
+ .isThrownBy(() -> new ControllerAdviceBean(null, null, null))
+ .withMessage("Bean name must contain text");
assertThatIllegalArgumentException()
- .isThrownBy(() -> new ControllerAdviceBean(null, null))
- .withMessage("Bean name must contain text");
+ .isThrownBy(() -> new ControllerAdviceBean(" ", null, null))
+ .withMessage("Bean name must contain text");
+ }
+ @Test
+ void shouldFailForNullBeanFactory() {
assertThatIllegalArgumentException()
- .isThrownBy(() -> new ControllerAdviceBean("", null))
- .withMessage("Bean name must contain text");
+ .isThrownBy(() -> new ControllerAdviceBean("beanName", null, null))
+ .withMessage("BeanFactory must not be null");
+ }
+ @Test
+ void shouldFailWhenBeanFactoryDoesNotContainBean() {
+ BeanFactory beanFactory = mock(BeanFactory.class);
+ given(beanFactory.containsBean(eq("beanName"))).willReturn(false);
assertThatIllegalArgumentException()
- .isThrownBy(() -> new ControllerAdviceBean("\t", null))
- .withMessage("Bean name must contain text");
+ .isThrownBy(() -> new ControllerAdviceBean("beanName", beanFactory, null))
+ .withMessageContaining("does not contain specified controller advice bean 'beanName'");
+ }
+ @Test
+ void shouldFailWhenControllerAdviceNull() {
+ BeanFactory beanFactory = mock(BeanFactory.class);
+ given(beanFactory.containsBean(eq("beanName"))).willReturn(true);
assertThatIllegalArgumentException()
- .isThrownBy(() -> new ControllerAdviceBean("myBean", null))
- .withMessage("BeanFactory must not be null");
+ .isThrownBy(() -> new ControllerAdviceBean("beanName", beanFactory, null))
+ .withMessage("ControllerAdvice must not be null");
}
@Test
void equalsHashCodeAndToStringForBeanName() {
- String beanName = "myBean";
- BeanFactory beanFactory = mock();
- given(beanFactory.containsBean(beanName)).willReturn(true);
-
- ControllerAdviceBean bean1 = new ControllerAdviceBean(beanName, beanFactory);
- ControllerAdviceBean bean2 = new ControllerAdviceBean(beanName, beanFactory);
+ String beanName = SimpleControllerAdvice.class.getSimpleName();
+ ControllerAdviceBean bean1 = createControllerAdviceBean(SimpleControllerAdvice.class);
+ ControllerAdviceBean bean2 = createControllerAdviceBean(SimpleControllerAdvice.class);
assertEqualsHashCodeAndToString(bean1, bean2, beanName);
}
- @Test
- void equalsHashCodeAndToStringForBeanInstance() {
- String toString = "beanInstance";
- Object beanInstance = new Object() {
- @Override
- public String toString() {
- return toString;
- }
- };
- ControllerAdviceBean bean1 = new ControllerAdviceBean(beanInstance);
- ControllerAdviceBean bean2 = new ControllerAdviceBean(beanInstance);
- assertEqualsHashCodeAndToString(bean1, bean2, toString);
- }
-
@Test
void orderedWithLowestPrecedenceByDefaultForBeanName() {
assertOrder(SimpleControllerAdvice.class, Ordered.LOWEST_PRECEDENCE);
@@ -103,7 +102,7 @@ class ControllerAdviceBeanTests {
@Test
void orderedWithLowestPrecedenceByDefaultForBeanInstance() {
- assertOrder(new SimpleControllerAdvice(), Ordered.LOWEST_PRECEDENCE);
+ assertOrder(SimpleControllerAdvice.class, Ordered.LOWEST_PRECEDENCE);
}
@Test
@@ -113,7 +112,7 @@ class ControllerAdviceBeanTests {
@Test
void orderedViaOrderedInterfaceForBeanInstance() {
- assertOrder(new OrderedControllerAdvice(), 42);
+ assertOrder(OrderedControllerAdvice.class, 42);
}
@Test
@@ -124,13 +123,13 @@ class ControllerAdviceBeanTests {
@Test
void orderedViaAnnotationForBeanInstance() {
- assertOrder(new OrderAnnotationControllerAdvice(), 100);
- assertOrder(new PriorityAnnotationControllerAdvice(), 200);
+ assertOrder(OrderAnnotationControllerAdvice.class, 100);
+ assertOrder(PriorityAnnotationControllerAdvice.class, 200);
}
@Test
void shouldMatchAll() {
- ControllerAdviceBean bean = new ControllerAdviceBean(new SimpleControllerAdvice());
+ ControllerAdviceBean bean = createControllerAdviceBean(SimpleControllerAdvice.class);
assertApplicable("should match all", bean, AnnotatedController.class);
assertApplicable("should match all", bean, ImplementationController.class);
assertApplicable("should match all", bean, InheritanceController.class);
@@ -139,7 +138,7 @@ class ControllerAdviceBeanTests {
@Test
void basePackageSupport() {
- ControllerAdviceBean bean = new ControllerAdviceBean(new BasePackageSupport());
+ ControllerAdviceBean bean = createControllerAdviceBean(BasePackageSupport.class);
assertApplicable("base package support", bean, AnnotatedController.class);
assertApplicable("base package support", bean, ImplementationController.class);
assertApplicable("base package support", bean, InheritanceController.class);
@@ -148,7 +147,7 @@ class ControllerAdviceBeanTests {
@Test
void basePackageValueSupport() {
- ControllerAdviceBean bean = new ControllerAdviceBean(new BasePackageValueSupport());
+ ControllerAdviceBean bean = createControllerAdviceBean(BasePackageValueSupport.class);
assertApplicable("base package support", bean, AnnotatedController.class);
assertApplicable("base package support", bean, ImplementationController.class);
assertApplicable("base package support", bean, InheritanceController.class);
@@ -157,14 +156,14 @@ class ControllerAdviceBeanTests {
@Test
void annotationSupport() {
- ControllerAdviceBean bean = new ControllerAdviceBean(new AnnotationSupport());
+ ControllerAdviceBean bean = createControllerAdviceBean(AnnotationSupport.class);
assertApplicable("annotation support", bean, AnnotatedController.class);
assertNotApplicable("this bean is not annotated", bean, InheritanceController.class);
}
@Test
void markerClassSupport() {
- ControllerAdviceBean bean = new ControllerAdviceBean(new MarkerClassSupport());
+ ControllerAdviceBean bean = createControllerAdviceBean(MarkerClassSupport.class);
assertApplicable("base package class support", bean, AnnotatedController.class);
assertApplicable("base package class support", bean, ImplementationController.class);
assertApplicable("base package class support", bean, InheritanceController.class);
@@ -173,7 +172,7 @@ class ControllerAdviceBeanTests {
@Test
void shouldNotMatch() {
- ControllerAdviceBean bean = new ControllerAdviceBean(new ShouldNotMatch());
+ ControllerAdviceBean bean = createControllerAdviceBean(ShouldNotMatch.class);
assertNotApplicable("should not match", bean, AnnotatedController.class);
assertNotApplicable("should not match", bean, ImplementationController.class);
assertNotApplicable("should not match", bean, InheritanceController.class);
@@ -182,7 +181,7 @@ class ControllerAdviceBeanTests {
@Test
void assignableTypesSupport() {
- ControllerAdviceBean bean = new ControllerAdviceBean(new AssignableTypesSupport());
+ ControllerAdviceBean bean = createControllerAdviceBean(AssignableTypesSupport.class);
assertApplicable("controller implements assignable", bean, ImplementationController.class);
assertApplicable("controller inherits assignable", bean, InheritanceController.class);
assertNotApplicable("not assignable", bean, AnnotatedController.class);
@@ -191,7 +190,7 @@ class ControllerAdviceBeanTests {
@Test
void multipleMatch() {
- ControllerAdviceBean bean = new ControllerAdviceBean(new MultipleSelectorsSupport());
+ ControllerAdviceBean bean = createControllerAdviceBean(MultipleSelectorsSupport.class);
assertApplicable("controller implements assignable", bean, ImplementationController.class);
assertApplicable("controller is annotated", bean, AnnotatedController.class);
assertNotApplicable("should not match", bean, InheritanceController.class);
@@ -201,14 +200,14 @@ class ControllerAdviceBeanTests {
@SuppressWarnings({"rawtypes", "unchecked"})
public void findAnnotatedBeansSortsBeans() {
Class[] expectedTypes = {
- // Since ControllerAdviceBean currently treats PriorityOrdered the same as Ordered,
- // OrderedControllerAdvice is sorted before PriorityOrderedControllerAdvice.
- OrderedControllerAdvice.class,
- PriorityOrderedControllerAdvice.class,
- OrderAnnotationControllerAdvice.class,
- PriorityAnnotationControllerAdvice.class,
- SimpleControllerAdviceWithBeanOrder.class,
- SimpleControllerAdvice.class,
+ // Since ControllerAdviceBean currently treats PriorityOrdered the same as Ordered,
+ // OrderedControllerAdvice is sorted before PriorityOrderedControllerAdvice.
+ OrderedControllerAdvice.class,
+ PriorityOrderedControllerAdvice.class,
+ OrderAnnotationControllerAdvice.class,
+ PriorityAnnotationControllerAdvice.class,
+ SimpleControllerAdviceWithBeanOrder.class,
+ SimpleControllerAdvice.class,
};
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
@@ -217,6 +216,13 @@ class ControllerAdviceBeanTests {
assertThat(adviceBeans).extracting(ControllerAdviceBean::getBeanType).containsExactly(expectedTypes);
}
+ private ControllerAdviceBean createControllerAdviceBean(Class> beanType) {
+ String beanName = beanType.getSimpleName();
+ this.applicationContext.registerSingleton(beanName, beanType);
+ ControllerAdvice controllerAdvice = AnnotatedElementUtils.findMergedAnnotation(beanType, ControllerAdvice.class);
+ return new ControllerAdviceBean(beanName, this.applicationContext, controllerAdvice);
+ }
+
private void assertEqualsHashCodeAndToString(ControllerAdviceBean bean1, ControllerAdviceBean bean2, String toString) {
assertThat(bean1).isEqualTo(bean2);
assertThat(bean2).isEqualTo(bean1);
@@ -225,24 +231,8 @@ class ControllerAdviceBeanTests {
assertThat(bean2.toString()).isEqualTo(toString);
}
- private void assertOrder(Object bean, int expectedOrder) {
- assertThat(new ControllerAdviceBean(bean).getOrder()).isEqualTo(expectedOrder);
- }
-
- @SuppressWarnings({"rawtypes", "unchecked"})
- private void assertOrder(Class beanType, int expectedOrder) {
- String beanName = "myBean";
- BeanFactory beanFactory = mock();
- given(beanFactory.containsBean(beanName)).willReturn(true);
- given(beanFactory.getType(beanName)).willReturn(beanType);
- given(beanFactory.getBean(beanName)).willReturn(BeanUtils.instantiateClass(beanType));
-
- ControllerAdviceBean controllerAdviceBean = new ControllerAdviceBean(beanName, beanFactory);
-
- assertThat(controllerAdviceBean.getOrder()).isEqualTo(expectedOrder);
- verify(beanFactory).containsBean(beanName);
- verify(beanFactory).getType(beanName);
- verify(beanFactory).getBean(beanName);
+ private void assertOrder(Class> beanType, int expectedOrder) {
+ assertThat(createControllerAdviceBean(beanType).getOrder()).isEqualTo(expectedOrder);
}
private void assertApplicable(String message, ControllerAdviceBean controllerAdvice, Class> controllerBeanType) {
@@ -259,18 +249,22 @@ class ControllerAdviceBeanTests {
// ControllerAdvice classes
@ControllerAdvice
- static class SimpleControllerAdvice {}
+ static class SimpleControllerAdvice {
+ }
@ControllerAdvice
- static class SimpleControllerAdviceWithBeanOrder {}
+ static class SimpleControllerAdviceWithBeanOrder {
+ }
@ControllerAdvice
@Order(100)
- static class OrderAnnotationControllerAdvice {}
+ static class OrderAnnotationControllerAdvice {
+ }
@ControllerAdvice
@Priority(200)
- static class PriorityAnnotationControllerAdvice {}
+ static class PriorityAnnotationControllerAdvice {
+ }
@ControllerAdvice
// @Order and @Priority should be ignored due to implementation of Ordered.
@@ -297,45 +291,59 @@ class ControllerAdviceBeanTests {
}
@ControllerAdvice(annotations = ControllerAnnotation.class)
- static class AnnotationSupport {}
+ static class AnnotationSupport {
+ }
@ControllerAdvice(basePackageClasses = MarkerClass.class)
- static class MarkerClassSupport {}
+ static class MarkerClassSupport {
+ }
@ControllerAdvice(assignableTypes = {ControllerInterface.class,
AbstractController.class})
- static class AssignableTypesSupport {}
+ static class AssignableTypesSupport {
+ }
@ControllerAdvice(basePackages = "org.springframework.web.method")
- static class BasePackageSupport {}
+ static class BasePackageSupport {
+ }
@ControllerAdvice("org.springframework.web.method")
- static class BasePackageValueSupport {}
+ static class BasePackageValueSupport {
+ }
@ControllerAdvice(annotations = ControllerAnnotation.class, assignableTypes = ControllerInterface.class)
- static class MultipleSelectorsSupport {}
+ static class MultipleSelectorsSupport {
+ }
@ControllerAdvice(basePackages = "java.util", annotations = {RestController.class})
- static class ShouldNotMatch {}
+ static class ShouldNotMatch {
+ }
// Support classes
- static class MarkerClass {}
+ static class MarkerClass {
+ }
@Retention(RetentionPolicy.RUNTIME)
- @interface ControllerAnnotation {}
+ @interface ControllerAnnotation {
+ }
@ControllerAnnotation
- public static class AnnotatedController {}
+ public static class AnnotatedController {
+ }
- interface ControllerInterface {}
+ interface ControllerInterface {
+ }
- static class ImplementationController implements ControllerInterface {}
+ static class ImplementationController implements ControllerInterface {
+ }
- abstract static class AbstractController {}
+ abstract static class AbstractController {
+ }
- static class InheritanceController extends AbstractController {}
+ static class InheritanceController extends AbstractController {
+ }
@Configuration(proxyBeanMethods = false)
static class Config {
diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyAdviceChainTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyAdviceChainTests.java
index 0c95016571a..c2bbb5a5776 100644
--- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyAdviceChainTests.java
+++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyAdviceChainTests.java
@@ -23,7 +23,9 @@ import java.util.List;
import org.junit.jupiter.api.Test;
+import org.springframework.context.support.StaticApplicationContext;
import org.springframework.core.MethodParameter;
+import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
@@ -109,7 +111,7 @@ class RequestResponseBodyAdviceChainTests {
@Test
void controllerAdvice() {
- Object adviceBean = new ControllerAdviceBean(new MyControllerAdvice());
+ Object adviceBean = createControllerAdviceBean(MyControllerAdvice.class);
RequestResponseBodyAdviceChain chain = new RequestResponseBodyAdviceChain(Collections.singletonList(adviceBean));
String actual = (String) chain.beforeBodyWrite(this.body, this.returnType, this.contentType,
@@ -120,7 +122,7 @@ class RequestResponseBodyAdviceChainTests {
@Test
void controllerAdviceNotApplicable() {
- Object adviceBean = new ControllerAdviceBean(new TargetedControllerAdvice());
+ Object adviceBean = createControllerAdviceBean(TargetedControllerAdvice.class);
RequestResponseBodyAdviceChain chain = new RequestResponseBodyAdviceChain(Collections.singletonList(adviceBean));
String actual = (String) chain.beforeBodyWrite(this.body, this.returnType, this.contentType,
@@ -129,6 +131,13 @@ class RequestResponseBodyAdviceChainTests {
assertThat(actual).isEqualTo(this.body);
}
+ private ControllerAdviceBean createControllerAdviceBean(Class> beanType) {
+ StaticApplicationContext applicationContext = new StaticApplicationContext();
+ applicationContext.registerSingleton(beanType.getSimpleName(), beanType);
+ ControllerAdvice controllerAdvice = AnnotatedElementUtils.findMergedAnnotation(beanType, ControllerAdvice.class);
+ return new ControllerAdviceBean(beanType.getSimpleName(), applicationContext, controllerAdvice);
+ }
+
@ControllerAdvice
private static class MyControllerAdvice implements ResponseBodyAdvice