custom stereotype annotations can be meta-annotated with @Service, @Controller etc as well; @Scope and @Transactional are now supported as meta-annotations on custom annotations

This commit is contained in:
Juergen Hoeller
2009-04-26 11:41:06 +00:00
parent ac16101f98
commit cea8f7f69e
18 changed files with 289 additions and 144 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2009 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.
@@ -21,14 +21,16 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.stereotype.Component;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
/**
* @author Juergen Hoeller
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Component
@Service
@Scope("prototype")
public @interface CustomStereotype {
String value() default "thoreau";

View File

@@ -69,6 +69,7 @@ public class ClassPathBeanDefinitionScannerTests {
FooServiceImpl service = context.getBean("fooServiceImpl", FooServiceImpl.class);
assertTrue(context.getDefaultListableBeanFactory().containsSingleton("myNamedComponent"));
assertEquals("bar", service.foo(1));
assertTrue(context.isPrototype("thoreau"));
}
@Test

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 the original author or authors.
* Copyright 2002-2009 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.
@@ -16,23 +16,10 @@
package org.springframework.context.annotation;
import static org.junit.Assert.*;
import java.util.Iterator;
import java.util.Set;
import java.util.regex.Pattern;
import org.junit.Test;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.core.type.filter.RegexPatternTypeFilter;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.util.ClassUtils;
import example.scannable.FooDao;
import example.scannable.FooService;
import example.scannable.FooServiceImpl;
@@ -41,6 +28,18 @@ import example.scannable.NamedComponent;
import example.scannable.NamedStubDao;
import example.scannable.ServiceInvocationCounter;
import example.scannable.StubFooDao;
import org.aspectj.lang.annotation.Aspect;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.core.type.filter.RegexPatternTypeFilter;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
/**
* @author Mark Fisher
@@ -95,7 +94,7 @@ public class ClassPathScanningCandidateComponentProviderTests {
provider.addExcludeFilter(new AnnotationTypeFilter(Service.class));
provider.addExcludeFilter(new AnnotationTypeFilter(Controller.class));
Set<BeanDefinition> candidates = provider.findCandidateComponents(TEST_BASE_PACKAGE);
assertEquals(3, candidates.size());
assertEquals(2, candidates.size());
assertTrue(containsBeanClass(candidates, NamedComponent.class));
assertTrue(containsBeanClass(candidates, ServiceInvocationCounter.class));
assertFalse(containsBeanClass(candidates, FooServiceImpl.class));
@@ -107,8 +106,7 @@ public class ClassPathScanningCandidateComponentProviderTests {
@Test
public void testWithAspectAnnotationOnly() throws Exception {
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
provider.addIncludeFilter(new AnnotationTypeFilter(
ClassUtils.forName("org.aspectj.lang.annotation.Aspect")));
provider.addIncludeFilter(new AnnotationTypeFilter(Aspect.class));
Set<BeanDefinition> candidates = provider.findCandidateComponents(TEST_BASE_PACKAGE);
assertEquals(1, candidates.size());
assertTrue(containsBeanClass(candidates, ServiceInvocationCounter.class));

View File

@@ -28,11 +28,12 @@ import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.StandardScopes;
import org.springframework.context.support.GenericApplicationContext;
/**
* Miscellaneous system tests covering {@link Bean} naming, aliases, scoping and error
@@ -64,14 +65,20 @@ public class ConfigurationClassProcessingTests {
@Test
public void customBeanNameIsRespected() {
BeanFactory factory = initBeanFactory(ConfigWithBeanWithCustomName.class);
assertSame(factory.getBean("customName"), ConfigWithBeanWithCustomName.testBean);
GenericApplicationContext ac = new GenericApplicationContext();
AnnotationConfigUtils.registerAnnotationConfigProcessors(ac);
ac.registerBeanDefinition("config", new RootBeanDefinition(ConfigWithBeanWithCustomName.class));
ac.refresh();
assertSame(ac.getBean("customName"), ConfigWithBeanWithCustomName.testBean);
// method name should not be registered
try {
factory.getBean("methodName");
ac.getBean("methodName");
fail("bean should not have been registered with 'methodName'");
} catch (NoSuchBeanDefinitionException ex) { /* expected */ }
}
catch (NoSuchBeanDefinitionException ex) {
// expected
}
}
@Test
@@ -165,7 +172,7 @@ public class ConfigurationClassProcessingTests {
return bar;
}
@Bean @Scope(StandardScopes.PROTOTYPE)
@Bean @Scope("prototype")
public TestBean baz() {
return new TestBean("bar");
}

View File

@@ -29,7 +29,6 @@ import test.beans.TestBean;
import org.springframework.aop.scope.ScopedObject;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
import static org.springframework.beans.factory.support.BeanDefinitionBuilder.*;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.Bean;
@@ -37,7 +36,6 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.context.annotation.StandardScopes;
import org.springframework.context.support.GenericApplicationContext;
/**
@@ -52,7 +50,9 @@ public class ScopingTests {
public static String flag = "1";
private static final String SCOPE = "my scope";
private CustomScope customScope;
private GenericApplicationContext ctx;
@Before
@@ -117,10 +117,8 @@ public class ScopingTests {
assertFalse(bean instanceof ScopedObject);
}
@Test
public void testScopedProxyConfiguration() throws Exception {
TestBean singleton = (TestBean) ctx.getBean("singletonWithScopedInterfaceDep");
ITestBean spouse = singleton.getSpouse();
assertTrue("scoped bean is not wrapped by the scoped-proxy", spouse instanceof ScopedObject);
@@ -224,7 +222,7 @@ public class ScopingTests {
static class ScopeTestConfiguration {
@Bean
@Scope(value=StandardScopes.SESSION, proxyMode=ScopedProxyMode.INTERFACES)
@Scope(value="session", proxyMode=ScopedProxyMode.INTERFACES)
public Foo foo() {
return new Foo();
}