revised support for annotated factory methods (merged @FactoryMethod functionality into JavaConfig facility)

This commit is contained in:
Juergen Hoeller
2009-04-19 23:45:31 +00:00
parent 736169aa2a
commit 14bd475519
84 changed files with 2411 additions and 3458 deletions

View File

@@ -21,12 +21,14 @@ import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.AsyncResult;
/**
* @author Mark Fisher
* @author Juergen Hoeller
*/
@Lazy
public class AutowiredQualifierFooService implements FooService {
@Autowired

View File

@@ -27,6 +27,8 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.ResourcePatternResolver;
@@ -38,7 +40,7 @@ import org.springframework.util.Assert;
* @author Mark Fisher
* @author Juergen Hoeller
*/
@Service
@Service @Lazy @DependsOn("myNamedComponent")
public class FooServiceImpl implements FooService {
@Autowired private FooDao fooDao;

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.
@@ -17,11 +17,12 @@
package example.scannable;
import org.springframework.stereotype.Component;
import org.springframework.context.annotation.Lazy;
/**
* @author Mark Fisher
*/
@Component("myNamedComponent")
@Component("myNamedComponent") @Lazy
public class NamedComponent {
}

View File

@@ -60,7 +60,8 @@ public abstract class AbstractCircularImportDetectionTests {
boolean threw = false;
try {
newParser().parse(loadAsConfigurationSource(X.class), null);
} catch (BeanDefinitionParsingException ex) {
}
catch (BeanDefinitionParsingException ex) {
assertTrue("Wrong message. Got: " + ex.getMessage(),
ex.getMessage().contains(
"Illegal attempt by @Configuration class 'AbstractCircularImportDetectionTests.Z2' " +
@@ -71,6 +72,7 @@ public abstract class AbstractCircularImportDetectionTests {
assertTrue(threw);
}
@Configuration
@Import(B.class)
static class A {
@Bean
@@ -79,6 +81,7 @@ public abstract class AbstractCircularImportDetectionTests {
}
}
@Configuration
@Import(A.class)
static class B {
@Bean
@@ -87,6 +90,7 @@ public abstract class AbstractCircularImportDetectionTests {
}
}
@Configuration
@Import( { Y.class, Z.class })
class X {
@Bean
@@ -95,6 +99,7 @@ public abstract class AbstractCircularImportDetectionTests {
}
}
@Configuration
class Y {
@Bean
TestBean y() {
@@ -102,6 +107,7 @@ public abstract class AbstractCircularImportDetectionTests {
}
}
@Configuration
@Import( { Z1.class, Z2.class })
class Z {
@Bean
@@ -110,6 +116,7 @@ public abstract class AbstractCircularImportDetectionTests {
}
}
@Configuration
class Z1 {
@Bean
TestBean z1() {
@@ -117,6 +124,7 @@ public abstract class AbstractCircularImportDetectionTests {
}
}
@Configuration
@Import(Z.class)
class Z2 {
@Bean
@@ -124,4 +132,5 @@ public abstract class AbstractCircularImportDetectionTests {
return new TestBean();
}
}
}

View File

@@ -1,18 +1,33 @@
/*
* Copyright 2002-2008 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.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
/**
* Unit tests for the {@link AnnotationScopeMetadataResolver} class.
*
* @author Rick Evans
* @author Chris Beams
* @author Juergen Hoeller
*/
public final class AnnotationScopeMetadataResolverTests {
@@ -34,7 +49,6 @@ public final class AnnotationScopeMetadataResolverTests {
assertEquals(ScopedProxyMode.NO, scopeMetadata.getScopedProxyMode());
}
@Test
public void testThatResolveScopeMetadataDoesApplyScopedProxyModeToAPrototype() {
this.scopeMetadataResolver = new AnnotationScopeMetadataResolver(ScopedProxyMode.INTERFACES);
@@ -45,6 +59,16 @@ public final class AnnotationScopeMetadataResolverTests {
assertEquals(ScopedProxyMode.INTERFACES, scopeMetadata.getScopedProxyMode());
}
@Test
public void testThatResolveScopeMetadataDoesReadScopedProxyModeFromTheAnnotation() {
this.scopeMetadataResolver = new AnnotationScopeMetadataResolver();
AnnotatedBeanDefinition bd = new AnnotatedGenericBeanDefinition(AnnotatedWithScopedProxy.class);
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(bd);
assertNotNull("resolveScopeMetadata(..) must *never* return null.", scopeMetadata);
assertEquals("request", scopeMetadata.getScopeName());
assertEquals(ScopedProxyMode.TARGET_CLASS, scopeMetadata.getScopedProxyMode());
}
@Test(expected=IllegalArgumentException.class)
public void testCtorWithNullScopedProxyMode() {
new AnnotationScopeMetadataResolver(null);
@@ -65,4 +89,9 @@ public final class AnnotationScopeMetadataResolverTests {
private static final class AnnotatedWithPrototypeScope {
}
@Scope(value="request", proxyMode = ScopedProxyMode.TARGET_CLASS)
private static final class AnnotatedWithScopedProxy {
}
}

View File

@@ -13,42 +13,40 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.context.annotation;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.springframework.context.annotation.AsmUtils.*;
import static org.springframework.context.annotation.ScopedProxyMode.*;
import static org.springframework.context.annotation.StandardScopes.*;
package org.springframework.context.annotation;
import java.lang.reflect.Modifier;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
import org.springframework.beans.factory.parsing.FailFastProblemReporter;
import org.springframework.beans.factory.parsing.Location;
import org.springframework.beans.factory.parsing.ProblemReporter;
import static org.springframework.context.annotation.ConfigurationClassReaderUtils.*;
import static org.springframework.context.annotation.ScopedProxyMode.*;
import static org.springframework.context.annotation.StandardScopes.*;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.ClassUtils;
/**
* Unit tests for {@link BeanMethod}.
*
* @author Chris Beams
*/
public class BeanMethodTests {
private ProblemReporter problemReporter = new FailFastProblemReporter();
private String beanName = "foo";
private Bean beanAnno = createMutableAnnotation(Bean.class, ClassUtils.getDefaultClassLoader());
private ModelClass returnType = new ModelClass("FooType");
private Bean beanAnno = (Bean) createMutableAnnotation(Bean.class, ClassUtils.getDefaultClassLoader());
private ConfigurationClassMethod.ReturnType returnType = new ConfigurationClassMethod.ReturnType("FooType");
private ConfigurationClass declaringClass = new ConfigurationClass();
{ declaringClass.setName("test.Config"); }
@Test
public void testWellFormedMethod() {
BeanMethod beanMethod = new BeanMethod(beanName, 0, returnType, beanAnno);
ConfigurationClassMethod beanMethod = new ConfigurationClassMethod(beanName, 0, returnType, beanAnno);
assertThat(beanMethod.getName(), sameInstance(beanName));
assertThat(beanMethod.getModifiers(), equalTo(0));
@@ -84,7 +82,7 @@ public class BeanMethodTests {
@Test
public void finalMethodsAreIllegal() {
BeanMethod beanMethod = new BeanMethod(beanName, Modifier.FINAL, returnType, beanAnno);
ConfigurationClassMethod beanMethod = new ConfigurationClassMethod(beanName, Modifier.FINAL, returnType, beanAnno);
beanMethod.setDeclaringClass(declaringClass);
try {
beanMethod.validate(problemReporter);
@@ -96,7 +94,7 @@ public class BeanMethodTests {
@Test
public void privateMethodsAreIllegal() {
BeanMethod beanMethod = new BeanMethod(beanName, Modifier.PRIVATE, returnType, beanAnno);
ConfigurationClassMethod beanMethod = new ConfigurationClassMethod(beanName, Modifier.PRIVATE, returnType, beanAnno);
beanMethod.setDeclaringClass(declaringClass);
try {
beanMethod.validate(problemReporter);
@@ -106,57 +104,18 @@ public class BeanMethodTests {
}
}
@Test
public void singletonInterfaceScopedProxiesAreIllegal() {
Scope scope = SingletonInterfaceProxy.class.getAnnotation(Scope.class);
BeanMethod beanMethod = new BeanMethod(beanName, 0, returnType, beanAnno, scope);
beanMethod.setDeclaringClass(declaringClass);
try {
beanMethod.validate(problemReporter);
fail("should have failed due to singleton with scoped proxy");
} catch (Exception ex) {
assertTrue(ex.getMessage().contains("cannot be created for singleton/prototype beans"));
}
}
@Test
public void singletonTargetClassScopedProxiesAreIllegal() {
Scope scope = SingletonTargetClassProxy.class.getAnnotation(Scope.class);
BeanMethod beanMethod = new BeanMethod(beanName, 0, returnType, beanAnno, scope);
beanMethod.setDeclaringClass(declaringClass);
try {
beanMethod.validate(problemReporter);
fail("should have failed due to singleton with scoped proxy");
} catch (Exception ex) {
assertTrue(ex.getMessage().contains("cannot be created for singleton/prototype beans"));
}
}
@Test
public void singletonsSansProxyAreLegal() {
Scope scope = SingletonNoProxy.class.getAnnotation(Scope.class);
BeanMethod beanMethod = new BeanMethod(beanName, 0, returnType, beanAnno, scope);
ConfigurationClassMethod beanMethod = new ConfigurationClassMethod(beanName, 0, returnType, beanAnno, scope);
beanMethod.setDeclaringClass(declaringClass);
beanMethod.validate(problemReporter); // should validate without problems - it's legal
}
@Test
public void prototypeInterfaceScopedProxiesAreIllegal() {
Scope scope = PrototypeInterfaceProxy.class.getAnnotation(Scope.class);
BeanMethod beanMethod = new BeanMethod(beanName, 0, returnType, beanAnno, scope);
beanMethod.setDeclaringClass(declaringClass);
try {
beanMethod.validate(problemReporter);
fail("should have failed due to prototype with scoped proxy");
} catch (Exception ex) {
assertTrue(ex.getMessage().contains("cannot be created for singleton/prototype beans"));
}
}
@Test
public void sessionInterfaceScopedProxiesAreLegal() {
Scope scope = SessionInterfaceProxy.class.getAnnotation(Scope.class);
BeanMethod beanMethod = new BeanMethod(beanName, 0, returnType, beanAnno, scope);
ConfigurationClassMethod beanMethod = new ConfigurationClassMethod(beanName, 0, returnType, beanAnno, scope);
beanMethod.setDeclaringClass(declaringClass);
beanMethod.validate(problemReporter); // should validate without problems - it's legal
}

View File

@@ -16,10 +16,15 @@
package org.springframework.context.annotation;
import static org.junit.Assert.*;
import example.scannable.CustomComponent;
import example.scannable.FooService;
import example.scannable.FooServiceImpl;
import example.scannable.NamedStubDao;
import example.scannable.StubFooDao;
import org.aspectj.lang.annotation.Aspect;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.beans.TestBean;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
@@ -34,12 +39,6 @@ import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.stereotype.Component;
import example.scannable.CustomComponent;
import example.scannable.FooService;
import example.scannable.FooServiceImpl;
import example.scannable.NamedStubDao;
import example.scannable.StubFooDao;
/**
* @author Mark Fisher
* @author Juergen Hoeller
@@ -49,7 +48,7 @@ public class ClassPathBeanDefinitionScannerTests {
private static final String BASE_PACKAGE = "example.scannable";
@Test
public void testSimpleScanWithDefaultFiltersAndPostProcessors() {
GenericApplicationContext context = new GenericApplicationContext();
@@ -62,9 +61,34 @@ public class ClassPathBeanDefinitionScannerTests {
assertTrue(context.containsBean("myNamedComponent"));
assertTrue(context.containsBean("myNamedDao"));
assertTrue(context.containsBean("thoreau"));
assertTrue(context.containsBean(AnnotationConfigUtils.CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
assertTrue(context.containsBean(AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
assertTrue(context.containsBean(AnnotationConfigUtils.REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
assertTrue(context.containsBean(AnnotationConfigUtils.COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
context.refresh();
FooServiceImpl service = context.getBean("fooServiceImpl", FooServiceImpl.class);
assertTrue(context.getDefaultListableBeanFactory().containsSingleton("myNamedComponent"));
assertEquals("bar", service.foo(1));
}
@Test
public void testSimpleScanWithDefaultFiltersAndPrimaryLazyBean() {
GenericApplicationContext context = new GenericApplicationContext();
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
scanner.scan(BASE_PACKAGE);
scanner.scan("org.springframework.context.annotation5");
assertTrue(context.containsBean("serviceInvocationCounter"));
assertTrue(context.containsBean("fooServiceImpl"));
assertTrue(context.containsBean("stubFooDao"));
assertTrue(context.containsBean("myNamedComponent"));
assertTrue(context.containsBean("myNamedDao"));
assertTrue(context.containsBean("otherFooDao"));
context.refresh();
assertFalse(context.getBeanFactory().containsSingleton("otherFooDao"));
assertFalse(context.getBeanFactory().containsSingleton("fooServiceImpl"));
FooServiceImpl service = context.getBean("fooServiceImpl", FooServiceImpl.class);
assertTrue(context.getBeanFactory().containsSingleton("otherFooDao"));
assertEquals("other", service.foo(1));
}
@Test
@@ -354,7 +378,7 @@ public class ClassPathBeanDefinitionScannerTests {
assertEquals(10, beanCount);
context.refresh();
FooServiceImpl fooService = (FooServiceImpl) context.getBean("fooService");
FooServiceImpl fooService = context.getBean("fooService", FooServiceImpl.class);
StaticListableBeanFactory myBf = (StaticListableBeanFactory) context.getBean("myBf");
MessageSource ms = (MessageSource) context.getBean("messageSource");
assertTrue(fooService.isInitCalled());
@@ -415,6 +439,7 @@ public class ClassPathBeanDefinitionScannerTests {
scanner.scan(BASE_PACKAGE);
try {
context.refresh();
context.getBean("fooService");
fail("BeanCreationException expected; fooDao should not have been an autowire-candidate");
}
catch (BeanCreationException expected) {

View File

@@ -16,91 +16,75 @@
package org.springframework.context.annotation;
import java.util.Set;
import junit.framework.TestCase;
import org.springframework.aop.scope.ScopedObject;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.TestBean;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.SimpleMapScope;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.AutowireCandidateQualifier;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation4.FactoryMethodComponent;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.util.ClassUtils;
/**
* @author Mark Pollack
* @author Juergen Hoeller
*/
public class ClassPathFactoryBeanDefinitionScannerTests extends TestCase {
private static final String BASE_PACKAGE = FactoryMethodComponent.class.getPackage().getName();
private static final int NUM_DEFAULT_BEAN_DEFS = 5;
private static final int NUM_FACTORY_METHODS = 5; // @ScopedProxy creates another
private static final int NUM_COMPONENT_DEFS = 1;
public void testSingletonScopedFactoryMethod()
{
public void testSingletonScopedFactoryMethod() {
GenericApplicationContext context = new GenericApplicationContext();
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
SimpleMapScope scope = new SimpleMapScope();
context.getBeanFactory().registerScope("request", scope);
int beanCount = scanner.scan(BASE_PACKAGE);
assertEquals(NUM_FACTORY_METHODS + NUM_COMPONENT_DEFS + NUM_DEFAULT_BEAN_DEFS, beanCount);
assertTrue(context.containsBean("factoryMethodComponent"));
assertTrue(context.containsBean("factoryMethodComponent$staticInstance"));
assertTrue(context.containsBean("factoryMethodComponent$getPublicInstance"));
context.getBeanFactory().registerScope("request", new SimpleMapScope());
TestBean staticTestBean = (TestBean)context.getBean("factoryMethodComponent$staticInstance");//1
assertEquals("staticInstance", staticTestBean.getName());
TestBean staticTestBean2 = (TestBean)context.getBean("factoryMethodComponent$staticInstance");//1
assertSame(staticTestBean, staticTestBean2);
TestBean tb = (TestBean)context.getBean("factoryMethodComponent$getPublicInstance"); //2
scanner.scan(BASE_PACKAGE);
context.registerBeanDefinition("clientBean", new RootBeanDefinition(QualifiedClientBean.class));
context.refresh();
FactoryMethodComponent fmc = context.getBean("factoryMethodComponent", FactoryMethodComponent.class);
assertFalse(fmc.getClass().getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR));
TestBean tb = (TestBean)context.getBean("publicInstance"); //2
assertEquals("publicInstance", tb.getName());
TestBean tb2 = (TestBean)context.getBean("factoryMethodComponent$getPublicInstance"); //2
TestBean tb2 = (TestBean)context.getBean("publicInstance"); //2
assertEquals("publicInstance", tb2.getName());
assertSame(tb2, tb);
//Were qualifiers applied to bean definition
ConfigurableListableBeanFactory cbf = (ConfigurableListableBeanFactory)context.getAutowireCapableBeanFactory();
AbstractBeanDefinition abd = (AbstractBeanDefinition)cbf.getBeanDefinition("factoryMethodComponent$getPublicInstance"); //2
Set<AutowireCandidateQualifier> qualifierSet = abd.getQualifiers();
assertEquals(1, qualifierSet.size());
tb = (TestBean)context.getBean("factoryMethodComponent$getProtectedInstance"); //3
tb = (TestBean)context.getBean("protectedInstance"); //3
assertEquals("protectedInstance", tb.getName());
tb2 = (TestBean)context.getBean("factoryMethodComponent$getProtectedInstance"); //3
assertSame(tb, context.getBean("protectedInstance"));
assertEquals("0", tb.getCountry());
tb2 = (TestBean)context.getBean("protectedInstance"); //3
assertEquals("protectedInstance", tb2.getName());
assertSame(tb2, tb);
tb = (TestBean)context.getBean("factoryMethodComponent$getPrivateInstance"); //4
tb = (TestBean)context.getBean("privateInstance"); //4
assertEquals("privateInstance", tb.getName());
assertEquals(0, tb.getAge());
tb2 = (TestBean)context.getBean("factoryMethodComponent$getPrivateInstance"); //4
assertEquals(1, tb2.getAge());
assertEquals(1, tb.getAge());
tb2 = (TestBean)context.getBean("privateInstance"); //4
assertEquals(2, tb2.getAge());
assertNotSame(tb2, tb);
Object bean = context.getBean("scopedTarget.factoryMethodComponent$requestScopedInstance"); //5
assertNotNull(bean);
assertTrue(bean instanceof ScopedObject);
//Scope assertions
Object bean = context.getBean("requestScopedInstance"); //5
assertTrue(AopUtils.isCglibProxy(bean));
assertTrue(bean instanceof ScopedObject);
QualifiedClientBean clientBean = context.getBean("clientBean", QualifiedClientBean.class);
assertSame(clientBean.testBean, context.getBean("publicInstance"));
}
public static class QualifiedClientBean {
@Autowired @Qualifier("public")
public TestBean testBean;
}
}

View File

@@ -13,104 +13,24 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.context.annotation;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.springframework.beans.factory.support.BeanDefinitionBuilder.*;
import java.lang.reflect.Field;
import java.util.Vector;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.util.ClassUtils;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
/**
* Unit tests for {@link ConfigurationClassPostProcessor}.
*
* @author Chris Beams
*/
public class ConfigurationClassPostProcessorTests {
private static final String ORIG_CGLIB_TEST_CLASS = ConfigurationClassPostProcessor.CGLIB_TEST_CLASS;
private static final String BOGUS_CGLIB_TEST_CLASS = "a.bogus.class";
/**
* CGLIB is an optional dependency for Spring. If users attempt
* to use {@link Configuration} classes, they'll need it on the classpath;
* if Configuration classes are present in the bean factory and CGLIB
* is not present, an instructive exception should be thrown.
*/
@Test
public void testFailFastIfCglibNotPresent() {
@Configuration class Config { }
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
factory.registerBeanDefinition("config", rootBeanDefinition(Config.class).getBeanDefinition());
ConfigurationClassPostProcessor cpp = new ConfigurationClassPostProcessor();
// temporarily set the cglib test class to something bogus
ConfigurationClassPostProcessor.CGLIB_TEST_CLASS = BOGUS_CGLIB_TEST_CLASS;
try {
cpp.postProcessBeanFactory(factory);
} catch (RuntimeException ex) {
assertTrue(ex.getMessage().contains("CGLIB is required to process @Configuration classes"));
} finally {
ConfigurationClassPostProcessor.CGLIB_TEST_CLASS = ORIG_CGLIB_TEST_CLASS;
}
}
/**
* In order to keep Spring's footprint as small as possible, CGLIB must
* not be required on the classpath unless the user is taking advantage
* of {@link Configuration} classes.
*
* This test will fail if any CGLIB classes are classloaded before the call
* to {@link ConfigurationClassPostProcessor#enhanceConfigurationClasses}
*/
@Ignore @Test // because classloader hacking below causes extremely hard to
// debug downstream side effects. Re-enable at will to verify
// CGLIB is not prematurely classloaded, but this technique is
// not stable enough to leave enabled.
public void testCglibClassesAreLoadedJustInTimeForEnhancement() throws Exception {
ClassLoader classLoader = ClassUtils.getDefaultClassLoader();
Field classesField = ClassLoader.class.getDeclaredField("classes");
classesField.setAccessible(true);
// first, remove any CGLIB classes that may have been loaded by other tests
@SuppressWarnings("unchecked")
Vector<Class<?>> classes = (Vector<Class<?>>) classesField.get(classLoader);
Vector<Class<?>> cglibClassesAlreadyLoaded = new Vector<Class<?>>();
for(Class<?> loadedClass : classes)
if(loadedClass.getName().startsWith("net.sf.cglib"))
cglibClassesAlreadyLoaded.add(loadedClass);
for(Class<?> cglibClass : cglibClassesAlreadyLoaded)
classes.remove(cglibClass);
// now, execute a scenario where everything except enhancement occurs
// -- no CGLIB classes should get loaded!
testFailFastIfCglibNotPresent();
// test to ensure that indeed no CGLIB classes have been loaded
for(Class<?> loadedClass : classes)
if(loadedClass.getName().startsWith("net.sf.cglib"))
fail("CGLIB class should not have been eagerly loaded: " + loadedClass.getName());
}
/**
* Enhanced {@link Configuration} classes are only necessary for respecting
* certain bean semantics, like singleton-scoping, scoped proxies, etc.
*
* Technically, {@link ConfigurationClassPostProcessor} could fail to enhance the
* <p>Technically, {@link ConfigurationClassPostProcessor} could fail to enhance the
* registered Configuration classes and many use cases would still work.
* Certain cases, however, like inter-bean singleton references would not.
* We test for such a case below, and in doing so prove that enhancement is
@@ -118,30 +38,13 @@ public class ConfigurationClassPostProcessorTests {
*/
@Test
public void testEnhancementIsPresentBecauseSingletonSemanticsAreRespected() {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerBeanDefinition("config",
rootBeanDefinition(SingletonBeanConfig.class).getBeanDefinition());
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(SingletonBeanConfig.class));
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
pp.postProcessBeanFactory(beanFactory);
Foo foo = (Foo) beanFactory.getBean("foo");
Bar bar = (Bar) beanFactory.getBean("bar");
assertThat(foo, sameInstance(bar.foo));
}
@Configuration
static class SingletonBeanConfig {
public @Bean Foo foo() {
return new Foo();
}
public @Bean Bar bar() {
return new Bar(foo());
}
}
static class Foo { }
static class Bar {
final Foo foo;
public Bar(Foo foo) { this.foo = foo; }
assertSame(foo, bar.foo);
}
/**
@@ -152,14 +55,38 @@ public class ConfigurationClassPostProcessorTests {
public void testAlreadyLoadedConfigurationClasses() {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerBeanDefinition("unloadedConfig",
rootBeanDefinition(UnloadedConfig.class.getName()).getBeanDefinition());
beanFactory.registerBeanDefinition("loadedConfig",
rootBeanDefinition(LoadedConfig.class).getBeanDefinition());
new ConfigurationClassPostProcessor() .postProcessBeanFactory(beanFactory);
new RootBeanDefinition(UnloadedConfig.class.getName(), null, null));
beanFactory.registerBeanDefinition("loadedConfig", new RootBeanDefinition(LoadedConfig.class));
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
pp.postProcessBeanFactory(beanFactory);
beanFactory.getBean("foo");
beanFactory.getBean("bar");
}
@Configuration
static class SingletonBeanConfig {
public @Bean Foo foo() {
return new Foo();
}
public @Bean Bar bar() {
return new Bar(foo());
}
}
static class Foo {
}
static class Bar {
final Foo foo;
public Bar(Foo foo) { this.foo = foo; }
}
@Configuration
static class UnloadedConfig {
public @Bean Foo foo() {
@@ -167,10 +94,12 @@ public class ConfigurationClassPostProcessorTests {
}
}
@Configuration
static class LoadedConfig {
public @Bean Bar bar() {
return new Bar(new Foo());
}
}
}

View File

@@ -1,48 +0,0 @@
/*
* 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.
* 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 java.lang.String.*;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.context.annotation.ConfigurationClass;
import org.springframework.context.annotation.ConfigurationModel;
/**
* Unit tests for {@link ConfigurationModel}.
*
* @author Chris Beams
*/
public class ConfigurationModelTests {
@Test
public void testToString() {
ConfigurationModel model = new ConfigurationModel();
assertThat(model.toString(), equalTo(
"ConfigurationModel containing @Configuration classes: []"));
ConfigurationClass config1 = new ConfigurationClass();
config1.setName("test.Config1");
model.add(config1);
assertThat(model.toString(), equalTo(format(
"ConfigurationModel containing @Configuration classes: [%s]", config1)));
}
}

View File

@@ -45,9 +45,11 @@ public class InvalidConfigurationClassDefinitionTests {
beanFactory.registerBeanDefinition("config", configBeanDef);
try {
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
pp.postProcessBeanFactory(beanFactory);
fail("expected exception");
} catch (BeanDefinitionParsingException ex) {
}
catch (BeanDefinitionParsingException ex) {
assertTrue(ex.getMessage(), ex.getMessage().contains("Remove the final modifier"));
}
}

View File

@@ -1,63 +0,0 @@
/*
* 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.
* 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.configuration;
import static org.junit.Assert.*;
import static org.springframework.beans.factory.support.BeanDefinitionBuilder.*;
import org.junit.Test;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
/**
* Covers the somewhat unlilely case of a {@link Configuration} class being declared
* as an abstract {@link BeanDefinition}.
*
* @author Chris Beams
* @see BeanDefinition#isAbstract()
*/
public class AbstractBeanDefinitionConfigurationClassTests {
@SuppressWarnings("unused")
@Test
public void abstractConfigurationClassBeanDefinitionsAreIgnored() {
@Configuration class Abstract { @Bean Object foo1() { return null; } }
@Configuration class Concrete { @Bean Object foo2() { return null; } }
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
factory.registerBeanDefinition("abstract",
rootBeanDefinition(Abstract.class).setAbstract(true).getBeanDefinition());
factory.registerBeanDefinition("concrete",
rootBeanDefinition(Concrete.class).setAbstract(false).getBeanDefinition());
new ConfigurationClassPostProcessor().postProcessBeanFactory(factory);
assertTrue("abstract configuration should be CGLIB-enhanced",
AopUtils.isCglibProxyClassName(factory.getBeanDefinition("abstract").getBeanClassName()));
assertTrue("concrete configuration should be CGLIB-enhanced",
AopUtils.isCglibProxyClassName(factory.getBeanDefinition("concrete").getBeanClassName()));
assertFalse("abstract configuration's @Bean method should not be registered",
factory.containsBeanDefinition("foo1"));
assertTrue("concrete configuration's @Bean method should be registered",
factory.containsBeanDefinition("foo2"));
}
}

View File

@@ -28,7 +28,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.DependsOn;
/**
* Unit tests proving that the various attributes available via the {@link Bean}
@@ -67,7 +67,7 @@ public class BeanAnnotationAttributePropagationTests {
@Test
public void dependsOnMetadataIsPropagated() {
@Configuration class Config {
@Bean(dependsOn={"bar", "baz"}) Object foo() { return null; }
@Bean() @DependsOn({"bar", "baz"}) Object foo() { return null; }
}
assertArrayEquals("dependsOn metadata was not propagated",
@@ -149,8 +149,8 @@ public class BeanAnnotationAttributePropagationTests {
private AbstractBeanDefinition beanDef(Class<?> configClass) {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
factory.registerBeanDefinition("config", new RootBeanDefinition(configClass));
new ConfigurationClassPostProcessor().postProcessBeanFactory(factory);
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
pp.postProcessBeanFactory(factory);
return (AbstractBeanDefinition) factory.getBeanDefinition("foo");
}

View File

@@ -16,27 +16,24 @@
package org.springframework.context.annotation.configuration;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.springframework.beans.factory.support.BeanDefinitionBuilder.*;
import org.junit.Test;
import test.beans.ITestBean;
import test.beans.TestBean;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
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.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 test.beans.ITestBean;
import test.beans.TestBean;
/**
* Miscellaneous system tests covering {@link Bean} naming, aliases, scoping and error
* handling within {@link Configuration} class definitions.
@@ -51,27 +48,20 @@ public class ConfigurationClassProcessingTests {
* post-processes the factory using JavaConfig's {@link ConfigurationClassPostProcessor}.
* When complete, the factory is ready to service requests for any {@link Bean} methods
* declared by <var>configClasses</var>.
*
* @param configClasses the {@link Configuration} classes under test. may be an empty
* list.
*
* @return fully initialized and post-processed {@link BeanFactory}
*/
private static BeanFactory initBeanFactory(Class<?>... configClasses) {
private BeanFactory initBeanFactory(Class<?>... configClasses) {
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
for (Class<?> configClass : configClasses) {
String configBeanName = configClass.getName();
factory.registerBeanDefinition(configBeanName, rootBeanDefinition(configClass).getBeanDefinition());
factory.registerBeanDefinition(configBeanName, new RootBeanDefinition(configClass));
}
new ConfigurationClassPostProcessor().postProcessBeanFactory(factory);
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
pp.postProcessBeanFactory(factory);
factory.addBeanPostProcessor(new AutowiredAnnotationBeanPostProcessor());
return factory;
}
@Test
public void customBeanNameIsRespected() {
BeanFactory factory = initBeanFactory(ConfigWithBeanWithCustomName.class);
@@ -132,20 +122,10 @@ public class ConfigurationClassProcessingTests {
@Test
public void simplestPossibleConfiguration() {
BeanFactory factory = initBeanFactory(SimplestPossibleConfig.class);
String stringBean = factory.getBean("stringBean", String.class);
assertThat(stringBean, equalTo("foo"));
assertEquals(stringBean, "foo");
}
@Configuration
static class SimplestPossibleConfig {
public @Bean String stringBean() {
return "foo";
}
}
@Test
public void configurationWithPrototypeScopedBeans() {
BeanFactory factory = initBeanFactory(ConfigWithPrototypeBean.class);
@@ -154,12 +134,22 @@ public class ConfigurationClassProcessingTests {
ITestBean bar = factory.getBean("bar", ITestBean.class);
ITestBean baz = factory.getBean("baz", ITestBean.class);
assertThat(foo.getSpouse(), sameInstance(bar));
assertThat(bar.getSpouse(), not(sameInstance(baz)));
assertSame(foo.getSpouse(), bar);
assertNotSame(bar.getSpouse(), baz);
}
@Configuration
static class SimplestPossibleConfig {
public @Bean String stringBean() {
return "foo";
}
}
@Configuration
static class ConfigWithPrototypeBean {
public @Bean TestBean foo() {
TestBean foo = new TestBean("foo");
foo.setSpouse(bar());

View File

@@ -41,9 +41,11 @@ public class ImportTests {
private DefaultListableBeanFactory processConfigurationClasses(Class<?>... classes) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
for (Class<?> clazz : classes)
for (Class<?> clazz : classes) {
beanFactory.registerBeanDefinition(clazz.getSimpleName(), new RootBeanDefinition(clazz));
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
}
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
pp.postProcessBeanFactory(beanFactory);
return beanFactory;
}
@@ -137,7 +139,8 @@ public class ImportTests {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(
WithMultipleArgumentsThatWillCauseDuplication.class));
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
pp.postProcessBeanFactory(beanFactory);
assertThat(beanFactory.getBeanDefinitionCount(), equalTo(4));
assertThat(beanFactory.getBean("foo", ITestBean.class).getName(), equalTo("foo2"));
}

View File

@@ -40,18 +40,23 @@ public class PolymorphicConfigurationTests {
public void subclassNeedNotDeclareConfigurationAnnotation() {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(Config.class));
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
pp.postProcessBeanFactory(beanFactory);
beanFactory.getBean("testBean", TestBean.class);
}
@Configuration
static class SuperConfig {
@Bean
public TestBean testBean() {
return new TestBean();
}
}
static class Config extends SuperConfig { }
static class Config extends SuperConfig {
}
}

View File

@@ -13,21 +13,24 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.context.annotation.configuration;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.springframework.beans.factory.support.BeanDefinitionBuilder.*;
package org.springframework.context.annotation.configuration;
import java.util.HashMap;
import java.util.Map;
import static org.hamcrest.CoreMatchers.*;
import org.junit.After;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import test.beans.ITestBean;
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;
import org.springframework.context.annotation.Configuration;
@@ -37,17 +40,12 @@ import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.context.annotation.StandardScopes;
import org.springframework.context.support.GenericApplicationContext;
import test.beans.ITestBean;
import test.beans.TestBean;
/**
* Tests that scopes are properly supported by using a custom Scope implementations
* and scoped proxy {@link Bean} declarations.
*
* @author Costin Leau
* @author Chris Beams
* @author Costin Leau
* @author Chris Beams
*/
public class ScopingTests {
@@ -82,19 +80,16 @@ public class ScopingTests {
return ctx;
}
@Test
public void testScopeOnClasses() throws Exception {
genericTestScope("scopedClass");
}
@Test
public void testScopeOnInterfaces() throws Exception {
genericTestScope("scopedInterface");
}
@Test
public void testSameScopeOnDifferentBeans() throws Exception {
Object beanAInScope = ctx.getBean("scopedClass");
@@ -112,22 +107,8 @@ public class ScopingTests {
assertNotSame(newBeanBInScope, beanBInScope);
}
@Test
public void testScopedProxyOnSingletonBeanMethod() throws Exception {
// should throw - scoped proxies should not be applied on singleton/prototype beans
try {
createContext(null, InvalidProxyOnPredefinedScopesConfiguration.class);
fail("exception expected");
} catch (BeanDefinitionParsingException ex) {
assertTrue(ex.getMessage().contains("scoped proxies cannot be created for singleton/prototype beans"));
}
}
@Test
public void testRawScopes() throws Exception {
String beanName = "scopedProxyInterface";
// get hidden bean
@@ -368,71 +349,56 @@ public class ScopingTests {
}
}
}
/**
* Simple scope implementation which creates object based on a flag.
*
* @author Costin Leau
* @author Chris Beams
*/
class CustomScope implements org.springframework.beans.factory.config.Scope {
public boolean createNewScope = true;
private Map<String, Object> beans = new HashMap<String, Object>();
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.config.Scope#get(java.lang.String,
* org.springframework.beans.factory.ObjectFactory)
/**
* Simple scope implementation which creates object based on a flag.
* @author Costin Leau
* @author Chris Beams
*/
public Object get(String name, ObjectFactory<?> objectFactory) {
if (createNewScope) {
beans.clear();
// reset the flag back
createNewScope = false;
static class CustomScope implements org.springframework.beans.factory.config.Scope {
public boolean createNewScope = true;
private Map<String, Object> beans = new HashMap<String, Object>();
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.config.Scope#get(java.lang.String,
* org.springframework.beans.factory.ObjectFactory)
*/
public Object get(String name, ObjectFactory<?> objectFactory) {
if (createNewScope) {
beans.clear();
// reset the flag back
createNewScope = false;
}
Object bean = beans.get(name);
// if a new object is requested or none exists under the current
// name, create one
if (bean == null) {
beans.put(name, objectFactory.getObject());
}
return beans.get(name);
}
Object bean = beans.get(name);
// if a new object is requested or none exists under the current
// name, create one
if (bean == null) {
beans.put(name, objectFactory.getObject());
public String getConversationId() {
return null;
}
return beans.get(name);
}
public void registerDestructionCallback(String name, Runnable callback) {
// do nothing
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.config.Scope#getConversationId()
*/
public String getConversationId() {
return null;
}
public Object remove(String name) {
return beans.remove(name);
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.config.Scope#registerDestructionCallback(java.lang.String,
* java.lang.Runnable)
*/
public void registerDestructionCallback(String name, Runnable callback) {
// do nothing
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.config.Scope#remove(java.lang.String)
*/
public Object remove(String name) {
return beans.remove(name);
}
public Object resolveContextualObject(String key) {
// TODO Auto-generated method stub
return null;
public Object resolveContextualObject(String key) {
// TODO Auto-generated method stub
return null;
}
}
}

View File

@@ -5,7 +5,7 @@
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:component-scan base-package="example.scannable"
<context:component-scan base-package="test, example.scannable"
name-generator="org.springframework.context.annotation.TestBeanNameGenerator"/>
</beans>

View File

@@ -17,63 +17,52 @@
package org.springframework.context.annotation4;
import org.springframework.beans.TestBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.FactoryMethod;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.ScopedProxy;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.BeanAge;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Component;
/**
* Class used to test the functionality of @FactoryMethod bean definitions declared inside
* a Spring @Component class.
*
* Class used to test the functionality of factory method bean definitions
* declared inside a Spring component class.
*
* @author Mark Pollack
* @author Juergen Hoeller
*/
@Component
public class FactoryMethodComponent {
public final class FactoryMethodComponent {
private static TestBean staticTestBean = new TestBean("staticInstance",1);
@Autowired @Qualifier("public")
public TestBean autowiredTestBean;
private static int i;
private int i;
@FactoryMethod @Qualifier("static")
public static TestBean staticInstance()
{
return staticTestBean;
}
public static TestBean nullInstance()
{
public static TestBean nullInstance() {
return null;
}
@FactoryMethod @Qualifier("public")
public TestBean getPublicInstance() {
@Bean @Qualifier("public")
public TestBean publicInstance() {
return new TestBean("publicInstance");
}
@FactoryMethod @BeanAge(1)
protected TestBean getProtectedInstance() {
return new TestBean("protectedInstance", 1);
@Bean @BeanAge(1)
protected TestBean protectedInstance(@Qualifier("public") TestBean spouse, @Value("#{privateInstance.age}") String country) {
TestBean tb = new TestBean("protectedInstance", 1);
tb.setSpouse(tb);
tb.setCountry(country);
return tb;
}
@FactoryMethod @Scope("prototype")
private TestBean getPrivateInstance() {
@Bean @Scope("prototype")
private TestBean privateInstance() {
return new TestBean("privateInstance", i++);
}
@FactoryMethod @Scope("request") @ScopedProxy
public TestBean requestScopedInstance()
{
TestBean testBean = new TestBean("requestScopedInstance", 3);
return testBean;
@Bean @Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public TestBean requestScopedInstance() {
return new TestBean("requestScopedInstance", 3);
}
//TODO method for test that fails if use @ScopedProxy with singleton scope.
}

View File

@@ -14,24 +14,23 @@
* limitations under the License.
*/
package org.springframework.context.annotation4;
import org.springframework.beans.TestBean;
import org.springframework.beans.factory.annotation.FactoryMethod;
import org.springframework.context.annotation.Bean;
/**
* Class to test that @FactoryMethods are detected only when inside a class with an @Component
* class annotation.
*
*
* @author Mark Pollack
*/
public class SimpleBean {
// This should *not* recognized as a @FactoryMethod since it does not reside inside an @Component
@FactoryMethod
// This should *not* recognized as a bean since it does not reside inside an @Component
@Bean
public TestBean getPublicInstance() {
return new TestBean("publicInstance");
}
}

View File

@@ -0,0 +1,36 @@
/*
* 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.
* 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.annotation5;
import example.scannable.FooDao;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Repository;
/**
* @author Juergen Hoeller
*/
@Repository
@Primary @Lazy
public class OtherFooDao implements FooDao {
public String findFoo(int id) {
return "other";
}
}

View File

@@ -209,7 +209,7 @@ public class ApplicationContextExpressionTests {
@Value("${code} #{systemProperties.country}")
public String country;
@Qualifier("original")
@Autowired @Qualifier("original")
public TestBean tb;
}
@@ -287,7 +287,7 @@ public class ApplicationContextExpressionTests {
this.country = country;
}
@Qualifier("original")
@Autowired @Qualifier("original")
public void setTb(TestBean tb) {
this.tb = tb;
}