revised support for annotated factory methods (merged @FactoryMethod functionality into JavaConfig facility)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user