diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java index ccb9e355051..2dabee201b3 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/AnnotationConfigUtils.java @@ -24,6 +24,7 @@ import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostP import org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.util.ClassUtils; @@ -215,6 +216,12 @@ public class AnnotationConfigUtils { String[] value = (String[]) abd.getMetadata().getAnnotationAttributes(DependsOn.class.getName()).get("value"); abd.setDependsOn(value); } + if (abd instanceof AbstractBeanDefinition) { + if (abd.getMetadata().isAnnotated(Role.class.getName())) { + int value = (Integer) abd.getMetadata().getAnnotationAttributes(Role.class.getName()).get("value"); + ((AbstractBeanDefinition)abd).setRole(value); + } + } } static BeanDefinitionHolder applyScopedProxyMode( diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java index 570f37afa09..2e4d8dbdc07 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java @@ -191,6 +191,13 @@ public class ConfigurationClassBeanDefinitionReader { beanDef.setAutowireMode(RootBeanDefinition.AUTOWIRE_CONSTRUCTOR); beanDef.setAttribute(RequiredAnnotationBeanPostProcessor.SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE); + // consider role + Map roleAttributes = metadata.getAnnotationAttributes(Role.class.getName()); + if (roleAttributes != null) { + int role = (Integer) roleAttributes.get("value"); + beanDef.setRole(role); + } + // consider name and any aliases Map beanAttributes = metadata.getAnnotationAttributes(Bean.class.getName()); List names = new ArrayList(Arrays.asList((String[]) beanAttributes.get("name"))); diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/Role.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/Role.java new file mode 100644 index 00000000000..3abdca32b17 --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/Role.java @@ -0,0 +1,62 @@ +/* + * Copyright 2002-2011 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 + * + * http://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.context.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.beans.factory.config.BeanDefinition; + +/** + * Indicates the 'role' hint for a given bean. + * + *

May be used on any class directly or indirectly annotated with + * {@link org.springframework.stereotype.Component} or on methods annotated with + * {@link Bean}. + * + *

If this annotation is not present on a Component or Bean definition, the + * default value of {@link BeanDefinition#ROLE_APPLICATION} will apply. + * + *

If Role is present on a {@link Configuration @Configuration} class, this + * indicates the role of the configuration class bean definition and does not + * cascade to all @{@code Bean} methods defined within. This behavior is + * different than that of the @{@link Lazy} annotation, for example. + * + * @author Chris Beams + * @since 3.1 + * @see BeanDefinition#ROLE_APPLICATION + * @see BeanDefinition#ROLE_INFRASTRUCTURE + * @see BeanDefinition#ROLE_SUPPORT + * @see Bean + */ +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface Role { + + /** + * Set the role hint for the associated bean. + * @see BeanDefinition#ROLE_APPLICATION + * @see BeanDefinition#ROLE_INFRASTRUCTURE + * @see BeanDefinition#ROLE_SUPPORT + */ + int value(); + +} diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/RoleAnnotationTests.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/RoleAnnotationTests.java new file mode 100644 index 00000000000..436ae5a9423 --- /dev/null +++ b/org.springframework.context/src/test/java/org/springframework/context/annotation/RoleAnnotationTests.java @@ -0,0 +1,85 @@ +/* + * Copyright 2002-2011 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 + * + * http://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.context.annotation; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +import org.junit.Test; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.annotation.role.ComponentWithRole; +import org.springframework.context.annotation.role.ComponentWithoutRole; + +/** + * Tests the use of the @Role annotation on @Bean methods and + * @Component classes. + * + * @author Chris Beams + * @since 3.1 + */ +public class RoleAnnotationTests { + + @Test + public void onBeanMethod() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + ctx.register(Config.class); + ctx.refresh(); + assertThat("Expected bean to have ROLE_APPLICATION", + ctx.getBeanDefinition("foo").getRole(), is(BeanDefinition.ROLE_APPLICATION)); + assertThat("Expected bean to have ROLE_INFRASTRUCTURE", + ctx.getBeanDefinition("bar").getRole(), is(BeanDefinition.ROLE_INFRASTRUCTURE)); + } + + + @Configuration + static class Config { + @Bean + public String foo() { + return "foo"; + } + + @Bean + @Role(BeanDefinition.ROLE_INFRASTRUCTURE) + public String bar() { + return "bar"; + } + } + + + @Test + public void onComponentClass() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + ctx.register(ComponentWithoutRole.class, ComponentWithRole.class); + ctx.refresh(); + assertThat("Expected bean to have ROLE_APPLICATION", + ctx.getBeanDefinition("componentWithoutRole").getRole(), is(BeanDefinition.ROLE_APPLICATION)); + assertThat("Expected bean to have ROLE_INFRASTRUCTURE", + ctx.getBeanDefinition("componentWithRole").getRole(), is(BeanDefinition.ROLE_INFRASTRUCTURE)); + } + + + @Test + public void viaComponentScanning() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + ctx.scan("org.springframework.context.annotation.role"); + ctx.refresh(); + assertThat("Expected bean to have ROLE_APPLICATION", + ctx.getBeanDefinition("componentWithoutRole").getRole(), is(BeanDefinition.ROLE_APPLICATION)); + assertThat("Expected bean to have ROLE_INFRASTRUCTURE", + ctx.getBeanDefinition("componentWithRole").getRole(), is(BeanDefinition.ROLE_INFRASTRUCTURE)); + } +} diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/role/ComponentWithRole.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/role/ComponentWithRole.java new file mode 100644 index 00000000000..85e8de9f82d --- /dev/null +++ b/org.springframework.context/src/test/java/org/springframework/context/annotation/role/ComponentWithRole.java @@ -0,0 +1,26 @@ +/* + * Copyright 2002-2011 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 + * + * http://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.context.annotation.role; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.annotation.Role; +import org.springframework.stereotype.Component; + +@Component("componentWithRole") +@Role(BeanDefinition.ROLE_INFRASTRUCTURE) +public class ComponentWithRole { +} \ No newline at end of file diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/role/ComponentWithoutRole.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/role/ComponentWithoutRole.java new file mode 100644 index 00000000000..860a3b35faf --- /dev/null +++ b/org.springframework.context/src/test/java/org/springframework/context/annotation/role/ComponentWithoutRole.java @@ -0,0 +1,23 @@ +/* + * Copyright 2002-2011 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 + * + * http://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.context.annotation.role; + +import org.springframework.stereotype.Component; + +@Component("componentWithoutRole") +public class ComponentWithoutRole { +} \ No newline at end of file