diff --git a/framework-docs/modules/ROOT/pages/core/beans/classpath-scanning.adoc b/framework-docs/modules/ROOT/pages/core/beans/classpath-scanning.adoc index 37c61a1208d..ebae0739733 100644 --- a/framework-docs/modules/ROOT/pages/core/beans/classpath-scanning.adoc +++ b/framework-docs/modules/ROOT/pages/core/beans/classpath-scanning.adoc @@ -675,7 +675,7 @@ As of Spring Framework 6.1, the name of the annotation attribute that is used to the bean name is no longer required to be `value`. Custom stereotype annotations can declare an attribute with a different name (such as `name`) and annotate that attribute with `@AliasFor(annotation = Component.class, attribute = "value")`. See the source code -declaration of `Repository#value()` for a concrete example. +declaration of `Repository#value()` and `ControllerAdvice#name()` for concrete examples. ==== If such an annotation contains no name `value` or for any other detected component diff --git a/spring-context/src/main/java/org/springframework/stereotype/Component.java b/spring-context/src/main/java/org/springframework/stereotype/Component.java index 3d679bb4061..94613659f93 100644 --- a/spring-context/src/main/java/org/springframework/stereotype/Component.java +++ b/spring-context/src/main/java/org/springframework/stereotype/Component.java @@ -35,7 +35,9 @@ import java.lang.annotation.Target; *

As of Spring Framework 6.1, custom component stereotype annotations should * use {@link org.springframework.core.annotation.AliasFor @AliasFor} to declare * an explicit alias for this annotation's {@link #value} attribute. See the - * source code declaration of {@link Repository#value()} for a concrete example. + * source code declaration of {@link Repository#value()} and + * {@link org.springframework.web.bind.annotation.ControllerAdvice#name() + * ControllerAdvice.name()} for concrete examples. * * @author Mark Fisher * @author Sam Brannen diff --git a/spring-web/src/main/java/org/springframework/web/bind/annotation/ControllerAdvice.java b/spring-web/src/main/java/org/springframework/web/bind/annotation/ControllerAdvice.java index 24cca20a939..57a28139d7f 100644 --- a/spring-web/src/main/java/org/springframework/web/bind/annotation/ControllerAdvice.java +++ b/spring-web/src/main/java/org/springframework/web/bind/annotation/ControllerAdvice.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2023 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. @@ -78,6 +78,13 @@ import org.springframework.stereotype.Component; @Component public @interface ControllerAdvice { + /** + * Alias for {@link Component#value}. + * @since 6.1 + */ + @AliasFor(annotation = Component.class, attribute = "value") + String name() default ""; + /** * Alias for the {@link #basePackages} attribute. *

Allows for more concise annotation declarations — for example, diff --git a/spring-web/src/main/java/org/springframework/web/bind/annotation/RestControllerAdvice.java b/spring-web/src/main/java/org/springframework/web/bind/annotation/RestControllerAdvice.java index e06bb6f1245..c819ee0a4da 100644 --- a/spring-web/src/main/java/org/springframework/web/bind/annotation/RestControllerAdvice.java +++ b/spring-web/src/main/java/org/springframework/web/bind/annotation/RestControllerAdvice.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2023 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. @@ -52,6 +52,13 @@ import org.springframework.core.annotation.AliasFor; @ResponseBody public @interface RestControllerAdvice { + /** + * Alias for {@link ControllerAdvice#name}. + * @since 6.1 + */ + @AliasFor(annotation = ControllerAdvice.class) + String name() default ""; + /** * Alias for the {@link #basePackages} attribute. *

Allows for more concise annotation declarations — for example, diff --git a/spring-web/src/test/java/org/springframework/web/bind/annotation/ComponentScannedControllerAdviceTests.java b/spring-web/src/test/java/org/springframework/web/bind/annotation/ComponentScannedControllerAdviceTests.java new file mode 100644 index 00000000000..539c421df75 --- /dev/null +++ b/spring-web/src/test/java/org/springframework/web/bind/annotation/ComponentScannedControllerAdviceTests.java @@ -0,0 +1,43 @@ +/* + * Copyright 2002-2023 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.junit.jupiter.api.Test; + +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Integration tests that verify support for component scanning + * {@link ControllerAdvice} and {@link RestControllerAdvice} beans. + * + * @author Sam Brannen + * @since 6.1 + */ +class ComponentScannedControllerAdviceTests { + + @Test + void scannedAdviceHasCustomName() { + String basePackage = getClass().getPackageName() + ".scanned"; + try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(basePackage)) { + assertThat(context.getBean("myControllerAdvice")).isNotNull(); + assertThat(context.getBean("myRestControllerAdvice")).isNotNull(); + } + } + +} diff --git a/spring-web/src/test/java/org/springframework/web/bind/annotation/scanned/ScannedControllerAdvice.java b/spring-web/src/test/java/org/springframework/web/bind/annotation/scanned/ScannedControllerAdvice.java new file mode 100644 index 00000000000..1cf60872f75 --- /dev/null +++ b/spring-web/src/test/java/org/springframework/web/bind/annotation/scanned/ScannedControllerAdvice.java @@ -0,0 +1,27 @@ +/* + * Copyright 2002-2023 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.scanned; + +import org.springframework.web.bind.annotation.ControllerAdvice; + +/** + * @author Sam Brannen + * @since 6.1 + */ +@ControllerAdvice(name = "myControllerAdvice", value = "org.my.pkg") +class ScannedControllerAdvice { +} diff --git a/spring-web/src/test/java/org/springframework/web/bind/annotation/scanned/ScannedRestControllerAdvice.java b/spring-web/src/test/java/org/springframework/web/bind/annotation/scanned/ScannedRestControllerAdvice.java new file mode 100644 index 00000000000..e0f324a6738 --- /dev/null +++ b/spring-web/src/test/java/org/springframework/web/bind/annotation/scanned/ScannedRestControllerAdvice.java @@ -0,0 +1,27 @@ +/* + * Copyright 2002-2023 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.scanned; + +import org.springframework.web.bind.annotation.RestControllerAdvice; + +/** + * @author Sam Brannen + * @since 6.1 + */ +@RestControllerAdvice(name = "myRestControllerAdvice", value = "org.my.pkg") +class ScannedRestControllerAdvice { +}