diff --git a/spring-context/src/main/java/org/springframework/context/annotation/Bean.java b/spring-context/src/main/java/org/springframework/context/annotation/Bean.java index 8cbaa0da3b1..8b4f45ac1de 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/Bean.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/Bean.java @@ -24,6 +24,7 @@ import java.lang.annotation.Target; import org.springframework.beans.factory.annotation.Autowire; import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.core.annotation.AliasFor; /** * Indicates that a method produces a bean to be managed by the Spring container. @@ -44,15 +45,15 @@ import org.springframework.beans.factory.support.AbstractBeanDefinition; * *
While a {@link #name() name} attribute is available, the default strategy for - * determining the name of a bean is to use the name of the {@code @Bean} method. - * This is convenient and intuitive, but if explicit naming is desired, the - * {@code name} attribute may be used. Also note that {@code name} accepts an array - * of Strings. This is in order to allow for specifying multiple names (i.e., aliases) - * for a single bean. + *
While a {@link #name} attribute is available, the default strategy for + * determining the name of a bean is to use the name of the {@code @Bean} method. This + * is convenient and intuitive, but if explicit naming is desired, the {@code name} + * attribute (or its alias {@code value}) may be used. Also note that {@code name} + * accepts an array of Strings. This is in order to allow for specifying multiple names + * (i.e., aliases) for a single bean. * *
- * @Bean(name={"b1","b2"}) // bean available as 'b1' and 'b2', but not 'myBean'
+ * @Bean({"b1","b2"}) // bean available as 'b1' and 'b2', but not 'myBean'
* public MyBean myBean() {
* // instantiate and configure MyBean obj
* return obj;
@@ -190,10 +191,24 @@ import org.springframework.beans.factory.support.AbstractBeanDefinition;
public @interface Bean {
/**
- * The name of this bean, or if plural, aliases for this bean. If left unspecified
- * the name of the bean is the name of the annotated method. If specified, the method
- * name is ignored.
+ * Alias for {@link #name}.
+ * Intended to be used when no other attributes are needed, for example:
+ * {@code @Bean("customBeanName")}.
+ * @since 5.0
+ * @see #name
*/
+ @AliasFor("name")
+ String[] value() default {};
+
+ /**
+ * The name of this bean, or if plural, aliases for this bean.
+ *
If left unspecified the name of the bean is the name of the annotated method.
+ * If specified, the method name is ignored.
+ *
The bean name and aliases may also be configured via the {@link #value}
+ * attribute if no other attributes are declared.
+ * @see #value
+ */
+ @AliasFor("value")
String[] name() default {};
/**
diff --git a/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassProcessingTests.java b/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassProcessingTests.java
index 1bf46027c19..b1360a5bf4f 100644
--- a/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassProcessingTests.java
+++ b/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassProcessingTests.java
@@ -20,9 +20,13 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
+import java.util.function.Supplier;
+
import javax.inject.Provider;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory;
@@ -65,6 +69,7 @@ import static org.junit.Assert.*;
*
* @author Chris Beams
* @author Juergen Hoeller
+ * @author Sam Brannen
*/
public class ConfigurationClassProcessingTests {
@@ -92,40 +97,57 @@ public class ConfigurationClassProcessingTests {
}
- @Test
- public void customBeanNameIsRespected() {
- GenericApplicationContext ac = new GenericApplicationContext();
- AnnotationConfigUtils.registerAnnotationConfigProcessors(ac);
- ac.registerBeanDefinition("config", new RootBeanDefinition(ConfigWithBeanWithCustomName.class));
- ac.refresh();
- assertSame(ac.getBean("customName"), ConfigWithBeanWithCustomName.testBean);
+ @Rule
+ public final ExpectedException exception = ExpectedException.none();
- // method name should not be registered
- try {
- ac.getBean("methodName");
- fail("bean should not have been registered with 'methodName'");
- }
- catch (NoSuchBeanDefinitionException ex) {
- // expected
- }
+
+ @Test
+ public void customBeanNameIsRespectedWhenConfiguredViaNameAttribute() {
+ customBeanNameIsRespected(ConfigWithBeanWithCustomName.class,
+ () -> ConfigWithBeanWithCustomName.testBean, "customName");
}
@Test
- public void aliasesAreRespected() {
- BeanFactory factory = initBeanFactory(ConfigWithBeanWithAliases.class);
- assertSame(factory.getBean("name1"), ConfigWithBeanWithAliases.testBean);
- String[] aliases = factory.getAliases("name1");
- for (String alias : aliases)
- assertSame(factory.getBean(alias), ConfigWithBeanWithAliases.testBean);
+ public void customBeanNameIsRespectedWhenConfiguredViaValueAttribute() {
+ customBeanNameIsRespected(ConfigWithBeanWithCustomNameConfiguredViaValueAttribute.class,
+ () -> ConfigWithBeanWithCustomNameConfiguredViaValueAttribute.testBean, "enigma");
+ }
+
+ private void customBeanNameIsRespected(Class> testClass, Supplier testBeanSupplier, String beanName) {
+ GenericApplicationContext ac = new GenericApplicationContext();
+ AnnotationConfigUtils.registerAnnotationConfigProcessors(ac);
+ ac.registerBeanDefinition("config", new RootBeanDefinition(testClass));
+ ac.refresh();
+
+ assertSame(testBeanSupplier.get(), ac.getBean(beanName));
// method name should not be registered
- try {
- factory.getBean("methodName");
- fail("bean should not have been registered with 'methodName'");
- }
- catch (NoSuchBeanDefinitionException ex) {
- // expected
- }
+ exception.expect(NoSuchBeanDefinitionException.class);
+ ac.getBean("methodName");
+ }
+
+ @Test
+ public void aliasesAreRespectedWhenConfiguredViaNameAttribute() {
+ aliasesAreRespected(ConfigWithBeanWithAliases.class,
+ () -> ConfigWithBeanWithAliases.testBean, "name1");
+ }
+
+ @Test
+ public void aliasesAreRespectedWhenConfiguredViaValueAttribute() {
+ aliasesAreRespected(ConfigWithBeanWithAliasesConfiguredViaValueAttribute.class,
+ () -> ConfigWithBeanWithAliasesConfiguredViaValueAttribute.testBean, "enigma");
+ }
+
+ private void aliasesAreRespected(Class> testClass, Supplier testBeanSupplier, String beanName) {
+ TestBean testBean = testBeanSupplier.get();
+ BeanFactory factory = initBeanFactory(testClass);
+
+ assertSame(testBean, factory.getBean(beanName));
+ Arrays.stream(factory.getAliases(beanName)).map(factory::getBean).forEach(alias -> assertSame(testBean, alias));
+
+ // method name should not be registered
+ exception.expect(NoSuchBeanDefinitionException.class);
+ factory.getBean("methodName");
}
@Test // SPR-11830
@@ -146,8 +168,9 @@ public class ConfigurationClassProcessingTests {
assertSame(ac.getBean("customName"), ConfigWithSetWithProviderImplementation.set);
}
- @Test(expected = BeanDefinitionParsingException.class)
+ @Test
public void testFinalBeanMethod() {
+ exception.expect(BeanDefinitionParsingException.class);
initBeanFactory(ConfigWithFinalBean.class);
}
@@ -219,6 +242,7 @@ public class ConfigurationClassProcessingTests {
adaptive = factory.getBean(AdaptiveInjectionPoints.class);
assertEquals("adaptiveInjectionPoint1", adaptive.adaptiveInjectionPoint1.getName());
assertEquals("setAdaptiveInjectionPoint2", adaptive.adaptiveInjectionPoint2.getName());
+ factory.close();
}
@Test
@@ -240,27 +264,49 @@ public class ConfigurationClassProcessingTests {
SpousyTestBean listener = factory.getBean("listenerTestBean", SpousyTestBean.class);
assertTrue(listener.refreshed);
+ factory.close();
}
@Configuration
static class ConfigWithBeanWithCustomName {
- static TestBean testBean = new TestBean();
+ static TestBean testBean = new TestBean(ConfigWithBeanWithCustomName.class.getSimpleName());
- @Bean(name="customName")
+ @Bean(name = "customName")
public TestBean methodName() {
return testBean;
}
}
+ @Configuration
+ static class ConfigWithBeanWithCustomNameConfiguredViaValueAttribute {
+
+ static TestBean testBean = new TestBean(ConfigWithBeanWithCustomNameConfiguredViaValueAttribute.class.getSimpleName());
+
+ @Bean("enigma")
+ public TestBean methodName() {
+ return testBean;
+ }
+ }
@Configuration
static class ConfigWithBeanWithAliases {
- static TestBean testBean = new TestBean();
+ static TestBean testBean = new TestBean(ConfigWithBeanWithAliases.class.getSimpleName());
- @Bean(name={"name1", "alias1", "alias2", "alias3"})
+ @Bean(name = { "name1", "alias1", "alias2", "alias3" })
+ public TestBean methodName() {
+ return testBean;
+ }
+ }
+
+ @Configuration
+ static class ConfigWithBeanWithAliasesConfiguredViaValueAttribute {
+
+ static TestBean testBean = new TestBean(ConfigWithBeanWithAliasesConfiguredViaValueAttribute.class.getSimpleName());
+
+ @Bean({ "enigma", "alias1", "alias2", "alias3" })
public TestBean methodName() {
return testBean;
}
@@ -270,9 +316,9 @@ public class ConfigurationClassProcessingTests {
@Configuration
static class ConfigWithBeanWithProviderImplementation implements Provider {
- static TestBean testBean = new TestBean();
+ static TestBean testBean = new TestBean(ConfigWithBeanWithProviderImplementation.class.getSimpleName());
- @Bean(name="customName")
+ @Bean(name = "customName")
public TestBean get() {
return testBean;
}
@@ -284,7 +330,7 @@ public class ConfigurationClassProcessingTests {
static Set set = Collections.singleton("value");
- @Bean(name="customName")
+ @Bean(name = "customName")
public Set get() {
return set;
}
diff --git a/spring-context/src/test/java/org/springframework/jmx/export/annotation/EnableMBeanExportConfigurationTests.java b/spring-context/src/test/java/org/springframework/jmx/export/annotation/EnableMBeanExportConfigurationTests.java
index 90488829522..d9d93306fdd 100644
--- a/spring-context/src/test/java/org/springframework/jmx/export/annotation/EnableMBeanExportConfigurationTests.java
+++ b/spring-context/src/test/java/org/springframework/jmx/export/annotation/EnableMBeanExportConfigurationTests.java
@@ -228,7 +228,7 @@ public class EnableMBeanExportConfigurationTests {
return new MBeanServerFactoryBean();
}
- @Bean(name="bean:name=testBean4")
+ @Bean("bean:name=testBean4")
@Lazy
public AnnotationTestBean testBean4() {
AnnotationTestBean bean = new AnnotationTestBean();
@@ -237,7 +237,7 @@ public class EnableMBeanExportConfigurationTests {
return bean;
}
- @Bean(name="bean:name=testBean5")
+ @Bean("bean:name=testBean5")
public AnnotationTestBeanFactory testBean5() throws Exception {
return new AnnotationTestBeanFactory();
}
diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupportTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupportTests.java
index 96177ee9d38..b31d35ffd48 100644
--- a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupportTests.java
+++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupportTests.java
@@ -333,10 +333,10 @@ public class WebMvcConfigurationSupportTests {
@EnableWebMvc
- @Configuration @SuppressWarnings("unused")
+ @Configuration
static class WebConfig {
- @Bean(name="/testController")
+ @Bean("/testController")
public TestController testController() {
return new TestController();
}
@@ -350,7 +350,7 @@ public class WebMvcConfigurationSupportTests {
}
- @Configuration @SuppressWarnings("unused")
+ @Configuration
static class ViewResolverConfig {
@Bean
@@ -387,7 +387,7 @@ public class WebMvcConfigurationSupportTests {
}
- @Controller @SuppressWarnings("unused")
+ @Controller
private static class TestController {
@RequestMapping("/")
@@ -413,7 +413,7 @@ public class WebMvcConfigurationSupportTests {
@Controller
- @Scope(value="prototype", proxyMode=ScopedProxyMode.TARGET_CLASS)
+ @Scope(scopeName = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
static class ScopedProxyController {
@RequestMapping("/scopedProxy")