Browse Source

Re-enabled support for @ScopedProxy

git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@734 50f2f4bb-b051-0410-bef5-90022cba6387
pull/1/head
Chris Beams 17 years ago
parent
commit
0aea9993eb
  1. 1
      org.springframework.config.java/src/main/java/org/springframework/config/java/Bean.java
  2. 26
      org.springframework.config.java/src/main/java/org/springframework/config/java/BeanMethod.java
  3. 75
      org.springframework.config.java/src/main/java/org/springframework/config/java/BeanRegistrar.java
  4. 1
      org.springframework.config.java/src/main/java/org/springframework/config/java/Configuration.java
  5. 33
      org.springframework.config.java/src/main/java/org/springframework/config/java/InvalidScopedProxyDeclarationError.java
  6. 92
      org.springframework.config.java/src/main/java/org/springframework/config/java/ScopedProxy.java
  7. 17
      org.springframework.config.java/src/main/java/org/springframework/config/java/internal/enhancement/BeanMethodInterceptor.java
  8. 4
      org.springframework.config.java/src/test/java/org/springframework/config/java/support/ConfigurationPostProcessorTests.java
  9. 89
      org.springframework.config.java/src/test/java/test/common/scope/CustomScope.java
  10. 374
      org.springframework.config.java/src/test/java/test/feature/lifecycle/scoping/ScopingTests.java

1
org.springframework.config.java/src/main/java/org/springframework/config/java/Bean.java

@ -57,6 +57,7 @@ import org.springframework.beans.factory.support.AbstractBeanDefinition;
* @author Rod Johnson * @author Rod Johnson
* @author Costin Leau * @author Costin Leau
* @author Chris Beams * @author Chris Beams
* @since 3.0
*/ */
@Target(ElementType.METHOD) @Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)

26
org.springframework.config.java/src/main/java/org/springframework/config/java/BeanMethod.java

@ -25,7 +25,6 @@ import java.util.List;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** TODO: JAVADOC */
public final class BeanMethod implements Validatable { public final class BeanMethod implements Validatable {
private final String name; private final String name;
@ -91,8 +90,8 @@ public final class BeanMethod implements Validatable {
T anno = getAnnotation(annoType); T anno = getAnnotation(annoType);
if (anno == null) if (anno == null)
throw new IllegalStateException(format("annotation %s not found on %s", annoType.getSimpleName(), throw new IllegalStateException(
this)); format("annotation %s not found on %s", annoType.getSimpleName(), this));
return anno; return anno;
} }
@ -123,8 +122,6 @@ public final class BeanMethod implements Validatable {
} }
public void validate(List<UsageError> errors) { public void validate(List<UsageError> errors) {
// for (Validator validator : validators)
// validator.validate(this, errors);
if (Modifier.isPrivate(getModifiers())) if (Modifier.isPrivate(getModifiers()))
errors.add(new PrivateMethodError()); errors.add(new PrivateMethodError());
@ -163,7 +160,7 @@ public final class BeanMethod implements Validatable {
public String toString() { public String toString() {
String returnTypeName = returnType == null ? "<unknown>" : returnType.getSimpleName(); String returnTypeName = returnType == null ? "<unknown>" : returnType.getSimpleName();
return String.format("%s: name=%s; returnType=%s; modifiers=%d", getClass().getSimpleName(), name, return String.format("%s: name=%s; returnType=%s; modifiers=%d", getClass().getSimpleName(), name,
returnTypeName, modifiers); returnTypeName, modifiers);
} }
@Override @Override
@ -246,15 +243,14 @@ class BeanValidator implements Validator {
public void validate(Object object, List<UsageError> errors) { public void validate(Object object, List<UsageError> errors) {
BeanMethod method = (BeanMethod) object; BeanMethod method = (BeanMethod) object;
// TODO: re-enable for @ScopedProxy support if (method.getAnnotation(ScopedProxy.class) == null)
// if (method.getAnnotation(ScopedProxy.class) == null) return;
// return;
// Bean bean = method.getRequiredAnnotation(Bean.class);
// Bean bean = method.getRequiredAnnotation(Bean.class);
// if (bean.scope().equals(StandardScopes.SINGLETON)
// if (bean.scope().equals(DefaultScopes.SINGLETON) || bean.scope().equals(StandardScopes.PROTOTYPE))
// || bean.scope().equals(DefaultScopes.PROTOTYPE)) errors.add(new InvalidScopedProxyDeclarationError(method));
// errors.add(new InvalidScopedProxyDeclarationError(method));
} }
} }

75
org.springframework.config.java/src/main/java/org/springframework/config/java/BeanRegistrar.java

@ -7,6 +7,8 @@ import java.lang.reflect.Method;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.aop.framework.autoproxy.AutoProxyUtils;
import org.springframework.aop.scope.ScopedProxyFactoryBean;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinition;
@ -50,7 +52,7 @@ public class BeanRegistrar implements BeanDefinitionRegistrar {
if (bean.autowire() != AnnotationUtils.getDefaultValue(Bean.class, "autowire")) if (bean.autowire() != AnnotationUtils.getDefaultValue(Bean.class, "autowire"))
beanDef.setAutowireMode(bean.autowire().value()); beanDef.setAutowireMode(bean.autowire().value());
else if (defaults.defaultAutowire() != AnnotationUtils.getDefaultValue(Configuration.class, else if (defaults.defaultAutowire() != AnnotationUtils.getDefaultValue(Configuration.class,
"defaultAutowire")) "defaultAutowire"))
beanDef.setAutowireMode(defaults.defaultAutowire().value()); beanDef.setAutowireMode(defaults.defaultAutowire().value());
String beanName = method.getName(); String beanName = method.getName();
@ -70,9 +72,8 @@ public class BeanRegistrar implements BeanDefinitionRegistrar {
} }
// overriding is legal, return immediately // overriding is legal, return immediately
logger.info(format( logger.info(format("Skipping loading bean definition for %s: a definition for bean "
"Skipping loading bean definition for %s: a definition for bean '%s' already exists. " + "'%s' already exists. This is likely due to an override in XML.", method, beanName));
+ "This is likely due to an override in XML.", method, beanName));
return; return;
} }
} }
@ -104,39 +105,33 @@ public class BeanRegistrar implements BeanDefinitionRegistrar {
if (hasText(destroyMethodName)) if (hasText(destroyMethodName))
beanDef.setDestroyMethodName(destroyMethodName); beanDef.setDestroyMethodName(destroyMethodName);
// TODO: re-enable for @ScopedProxy support
// is this method annotated with @ScopedProxy? // is this method annotated with @ScopedProxy?
// ScopedProxy scopedProxy = method.getAnnotation(ScopedProxy.class); ScopedProxy scopedProxy = method.getAnnotation(ScopedProxy.class);
// if (scopedProxy != null) { if (scopedProxy != null) {
// RootBeanDefinition targetDef = beanDef; RootBeanDefinition targetDef = beanDef;
// //
// // Create a scoped proxy definition for the original bean name, // Create a scoped proxy definition for the original bean name,
// // "hiding" the target bean in an internal target definition. // "hiding" the target bean in an internal target definition.
// String targetBeanName = String targetBeanName = ScopedProxy.Util.resolveHiddenScopedProxyBeanName(beanName);
// ScopedProxy.Util.resolveHiddenScopedProxyBeanName(beanName); RootBeanDefinition scopedProxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);
// RootBeanDefinition scopedProxyDefinition = new scopedProxyDefinition.getPropertyValues().addPropertyValue("targetBeanName", targetBeanName);
// RootBeanDefinition(ScopedProxyFactoryBean.class);
// scopedProxyDefinition.getPropertyValues().addPropertyValue("targetBeanName", if (scopedProxy.proxyTargetClass())
// targetBeanName); targetDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
// // ScopedFactoryBean's "proxyTargetClass" default is TRUE, so we
// if (scopedProxy.proxyTargetClass()) // don't need to set it explicitly here.
// targetDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, else
// Boolean.TRUE); scopedProxyDefinition.getPropertyValues().addPropertyValue("proxyTargetClass", Boolean.FALSE);
// // ScopedFactoryBean's "proxyTargetClass" default is TRUE, so we
// // don't need to set it explicitly here. // The target bean should be ignored in favor of the scoped proxy.
// else targetDef.setAutowireCandidate(false);
// scopedProxyDefinition.getPropertyValues().addPropertyValue("proxyTargetClass",
// Boolean.FALSE); // Register the target bean as separate bean in the factory
// registry.registerBeanDefinition(targetBeanName, targetDef);
// // The target bean should be ignored in favor of the scoped proxy.
// targetDef.setAutowireCandidate(false); // replace the original bean definition with the target one
// beanDef = scopedProxyDefinition;
// // Register the target bean as separate bean in the factory }
// registry.registerBeanDefinition(targetBeanName, targetDef);
//
// // replace the original bean definition with the target one
// beanDef = scopedProxyDefinition;
// }
// TODO: re-enable for @Meta support // TODO: re-enable for @Meta support
// does this bean method have any @Meta annotations? // does this bean method have any @Meta annotations?
@ -147,8 +142,8 @@ public class BeanRegistrar implements BeanDefinitionRegistrar {
if (bean.dependsOn().length > 0) if (bean.dependsOn().length > 0)
beanDef.setDependsOn(bean.dependsOn()); beanDef.setDependsOn(bean.dependsOn());
logger.info(format("Registering bean definition for @Bean method %s.%s()", configClass.getName(), logger.info(format("Registering bean definition for @Bean method %s.%s()",
beanName)); configClass.getName(), beanName));
registry.registerBeanDefinition(beanName, beanDef); registry.registerBeanDefinition(beanName, beanDef);
@ -188,7 +183,7 @@ public class BeanRegistrar implements BeanDefinitionRegistrar {
} while (clbf != null); } while (clbf != null);
throw new NoSuchBeanDefinitionException(format("No bean definition matching name '%s' " throw new NoSuchBeanDefinitionException(format("No bean definition matching name '%s' "
+ "could be found in %s or its ancestry", beanName, registry)); + "could be found in %s or its ancestry", beanName, registry));
} }
} }
@ -201,4 +196,4 @@ public class BeanRegistrar implements BeanDefinitionRegistrar {
*/ */
@SuppressWarnings("serial") @SuppressWarnings("serial")
class ConfigurationClassBeanDefinition extends RootBeanDefinition { class ConfigurationClassBeanDefinition extends RootBeanDefinition {
} }

1
org.springframework.config.java/src/main/java/org/springframework/config/java/Configuration.java

@ -46,6 +46,7 @@ import org.springframework.stereotype.Component;
* *
* @author Rod Johnson * @author Rod Johnson
* @author Chris Beams * @author Chris Beams
* @since 3.0
*/ */
@Component @Component
@Target( { ElementType.TYPE }) @Target( { ElementType.TYPE })

33
org.springframework.config.java/src/main/java/org/springframework/config/java/InvalidScopedProxyDeclarationError.java

@ -0,0 +1,33 @@
/*
* 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.config.java;
public class InvalidScopedProxyDeclarationError extends UsageError {
private final BeanMethod method;
public InvalidScopedProxyDeclarationError(BeanMethod method) {
super(method.getDeclaringClass(), method.getLineNumber());
this.method = method;
}
@Override
public String getDescription() {
return String.format("method %s contains an invalid annotation declaration: @%s "
+ "cannot be used on a singleton/prototype bean", method.getName(), ScopedProxy.class
.getSimpleName());
}
}

92
org.springframework.config.java/src/main/java/org/springframework/config/java/ScopedProxy.java

@ -0,0 +1,92 @@
/*
* 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.config.java;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.util.Assert;
/**
* Annotation identical in functionality with &lt;aop:scoped-proxy/&gt; tag. Provides a smart
* proxy backed by a scoped bean, which can be injected into object instances (usually singletons)
* allowing the same reference to be held while delegating method invocations to the backing, scoped
* beans.
*
* <p/>Used with scoped beans (non-singleton and non-prototype).</p>
*
* <pre class="code">
* &#064;Configuration
* public class ScopedConfig {
*
* &#064;Bean(scope = &quot;myScope&quot;)
* &#064;ScopedProxy
* public SomeBean someBean() {
* return new SomeBean();
*  }
*
* &#064;Bean
* public SomeOtherBean() {
* return new AnotherBean(someBean());
* }
* }
* </pre>
*
* <p>See Spring reference <a href="http://static.springframework.org/spring/docs/2.5.x/reference/">
* documentation</a> for more <a
* href="http://static.springframework.org/spring/docs/2.5.x/reference/beans.html#beans-factory-scopes-other-injection">
* details</a>.</p>
*
* @author Costin Leau
* @author Chris Beams
* @since 3.0
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ScopedProxy {
/**
* Use CGLib-based class proxies (true) or JDK interface-based (false).
*
* Default is CGLib (true).
* @return
*/
boolean proxyTargetClass() default true;
public static class Util {
private static final String TARGET_NAME_PREFIX = "scopedTarget.";
/**
* Return the <i>hidden</i> name based on a scoped proxy bean name.
*
* @param originalBeanName the scope proxy bean name as declared in the
* Configuration-annotated class
*
* @return the internally-used <i>hidden</i> bean name
*/
public static String resolveHiddenScopedProxyBeanName(String originalBeanName) {
Assert.hasText(originalBeanName);
return TARGET_NAME_PREFIX.concat(originalBeanName);
}
}
}

17
org.springframework.config.java/src/main/java/org/springframework/config/java/internal/enhancement/BeanMethodInterceptor.java

@ -24,6 +24,8 @@ import net.sf.cglib.proxy.MethodProxy;
import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.config.java.Bean; import org.springframework.config.java.Bean;
import org.springframework.config.java.BeanRegistrar; import org.springframework.config.java.BeanRegistrar;
import org.springframework.config.java.ScopedProxy;
import org.springframework.core.annotation.AnnotationUtils;
/** /**
@ -44,14 +46,13 @@ class BeanMethodInterceptor extends AbstractMethodInterceptor {
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
String beanName = getBeanName(method); String beanName = getBeanName(method);
// TODO: re-enable for @ScopedProxy support boolean isScopedProxy =
// boolean isScopedProxy = (AnnotationUtils.findAnnotation(method, (AnnotationUtils.findAnnotation(method, ScopedProxy.class) != null);
// ScopedProxy.class) != null);
// String scopedBeanName =
// String scopedBeanName = ScopedProxy.Util.resolveHiddenScopedProxyBeanName(beanName);
// ScopedProxy.Util.resolveHiddenScopedProxyBeanName(beanName); if (isScopedProxy && beanFactory.isCurrentlyInCreation(scopedBeanName))
// if (isScopedProxy && beanFactory.isCurrentlyInCreation(scopedBeanName)) beanName = scopedBeanName;
// beanName = scopedBeanName;
if (factoryContainsBean(beanName)) { if (factoryContainsBean(beanName)) {
// we have an already existing cached instance of this bean -> retrieve it // we have an already existing cached instance of this bean -> retrieve it

4
org.springframework.config.java/src/test/java/org/springframework/config/java/support/ConfigurationPostProcessorTests.java

@ -110,7 +110,7 @@ public class ConfigurationPostProcessorTests {
* certain bean semantics, like singleton-scoping, scoped proxies, etc. * certain bean semantics, like singleton-scoping, scoped proxies, etc.
* *
* Technically, {@link ConfigurationClassPostProcessor} could fail to enhance the * Technically, {@link ConfigurationClassPostProcessor} could fail to enhance the
* registered Configuration classes, and many use cases would still work. * registered Configuration classes and many use cases would still work.
* Certain cases, however, like inter-bean singleton references would not. * 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 * We test for such a case below, and in doing so prove that enhancement is
* working. * working.
@ -142,5 +142,5 @@ public class ConfigurationPostProcessorTests {
final Foo foo; final Foo foo;
public Bar(Foo foo) { this.foo = foo; } public Bar(Foo foo) { this.foo = foo; }
} }
} }

89
org.springframework.config.java/src/test/java/test/common/scope/CustomScope.java

@ -0,0 +1,89 @@
/*
* 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 test.common.scope;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;
/**
* Simple scope implementation which creates object based on a flag.
*
* @author Costin Leau
* @author Chris Beams
*/
public class CustomScope implements 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);
}
/*
* (non-Javadoc)
* @see org.springframework.beans.factory.config.Scope#getConversationId()
*/
public String getConversationId() {
return null;
}
/*
* (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;
}
}

374
org.springframework.config.java/src/test/java/test/feature/lifecycle/scoping/ScopingTests.java

@ -0,0 +1,374 @@
/*
* 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 test.feature.lifecycle.scoping;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.springframework.beans.factory.support.BeanDefinitionBuilder.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.aop.scope.ScopedObject;
import org.springframework.beans.factory.config.Scope;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.config.java.Bean;
import org.springframework.config.java.Configuration;
import org.springframework.config.java.InvalidScopedProxyDeclarationError;
import org.springframework.config.java.MalformedConfigurationException;
import org.springframework.config.java.ScopedProxy;
import org.springframework.config.java.StandardScopes;
import org.springframework.config.java.support.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;
import test.beans.ITestBean;
import test.beans.TestBean;
import test.common.scope.CustomScope;
/**
* Tests that scopes are properly supported by using a custom {@link Scope} and
* {@link ScopedProxy} declarations.
*
* @see ScopeIntegrationTests
* @author Costin Leau
* @author Chris Beams
*/
public class ScopingTests {
public static String flag = "1";
private static final String SCOPE = "my scope";
private CustomScope customScope;
private GenericApplicationContext ctx;
@Before
public void setUp() throws Exception {
customScope = new CustomScope();
ctx = createContext(customScope, ScopedConfigurationClass.class);
}
@After
public void tearDown() throws Exception {
ctx.close();
ctx = null;
customScope = null;
}
private GenericApplicationContext createContext(Scope customScope, Class<?> configClass) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
if(customScope != null)
beanFactory.registerScope(SCOPE, customScope);
beanFactory.registerBeanDefinition("config",
rootBeanDefinition(configClass).getBeanDefinition());
GenericApplicationContext ctx = new GenericApplicationContext(beanFactory);
ctx.addBeanFactoryPostProcessor(new ConfigurationClassPostProcessor());
ctx.refresh();
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");
Object beanBInScope = ctx.getBean("scopedInterface");
assertNotSame(beanAInScope, beanBInScope);
customScope.createNewScope = true;
Object newBeanAInScope = ctx.getBean("scopedClass");
Object newBeanBInScope = ctx.getBean("scopedInterface");
assertNotSame(newBeanAInScope, newBeanBInScope);
assertNotSame(newBeanAInScope, beanAInScope);
assertNotSame(newBeanBInScope, beanBInScope);
}
@Test
public void testScopedProxyOnNonBeanAnnotatedMethod() throws Exception {
// should throw - @ScopedProxy should not be applied on singleton/prototype beans
try {
createContext(null, InvalidProxyOnPredefinedScopesConfiguration.class);
fail("exception expected");
} catch (MalformedConfigurationException ex) {
assertTrue(ex.containsError(InvalidScopedProxyDeclarationError.class));
}
}
@Test
public void testRawScopes() throws Exception {
String beanName = "scopedProxyInterface";
// get hidden bean
Object bean = ctx.getBean("scopedTarget." + beanName);
assertFalse(bean instanceof ScopedObject);
}
@Test
public void testScopedProxyConfiguration() throws Exception {
TestBean singleton = (TestBean) ctx.getBean("singletonWithScopedInterfaceDep");
ITestBean spouse = singleton.getSpouse();
assertTrue("scoped bean is not wrapped by the scoped-proxy", spouse instanceof ScopedObject);
String beanName = "scopedProxyInterface";
String scopedBeanName = ScopedProxy.Util.resolveHiddenScopedProxyBeanName(beanName);
// get hidden bean
assertEquals(flag, spouse.getName());
ITestBean spouseFromBF = (ITestBean) ctx.getBean(scopedBeanName);
assertEquals(spouse.getName(), spouseFromBF.getName());
// the scope proxy has kicked in
assertNotSame(spouse, spouseFromBF);
// create a new bean
customScope.createNewScope = true;
// get the bean again from the BF
spouseFromBF = (ITestBean) ctx.getBean(scopedBeanName);
// make sure the name has been updated
assertSame(spouse.getName(), spouseFromBF.getName());
assertNotSame(spouse, spouseFromBF);
// get the bean again
spouseFromBF = (ITestBean) ctx.getBean(scopedBeanName);
assertSame(spouse.getName(), spouseFromBF.getName());
}
@Test
public void testScopedProxyConfigurationWithClasses() throws Exception {
TestBean singleton = (TestBean) ctx.getBean("singletonWithScopedClassDep");
ITestBean spouse = singleton.getSpouse();
assertTrue("scoped bean is not wrapped by the scoped-proxy", spouse instanceof ScopedObject);
String beanName = "scopedProxyClass";
String scopedBeanName = ScopedProxy.Util.resolveHiddenScopedProxyBeanName(beanName);
// get hidden bean
assertEquals(flag, spouse.getName());
TestBean spouseFromBF = (TestBean) ctx.getBean(scopedBeanName);
assertEquals(spouse.getName(), spouseFromBF.getName());
// the scope proxy has kicked in
assertNotSame(spouse, spouseFromBF);
// create a new bean
customScope.createNewScope = true;
flag = "boo";
// get the bean again from the BF
spouseFromBF = (TestBean) ctx.getBean(scopedBeanName);
// make sure the name has been updated
assertSame(spouse.getName(), spouseFromBF.getName());
assertNotSame(spouse, spouseFromBF);
// get the bean again
spouseFromBF = (TestBean) ctx.getBean(scopedBeanName);
assertSame(spouse.getName(), spouseFromBF.getName());
}
@Test
public void testScopedConfigurationBeanDefinitionCount() throws Exception {
// count the beans
// 6 @Beans + 1 Configuration + 2 @ScopedProxy
assertThat(ctx.getBeanDefinitionCount(), equalTo(9));
}
// /**
// * SJC-254 caught a regression in handling scoped proxies starting in 1.0 m4.
// * The ScopedProxyFactoryBean object was having its scope set to that of its delegate
// * whereas it should have remained singleton.
// */
// @Test
// public void sjc254() {
// JavaConfigWebApplicationContext ctx = new JavaConfigWebApplicationContext();
// ctx.setConfigLocations(new String[] { ScopeTestConfiguration.class.getName() });
// ctx.refresh();
//
// // should be fine
// ctx.getBean(Bar.class);
//
// boolean threw = false;
// try {
// ctx.getBean(Foo.class);
// } catch (BeanCreationException ex) {
// if(ex.getCause() instanceof IllegalStateException) {
// threw = true;
// }
// }
// assertTrue(threw);
// }
@Configuration
static class ScopeTestConfiguration {
@Bean(scope = StandardScopes.SESSION)
@ScopedProxy
public Foo foo() {
return new Foo();
}
@Bean
public Bar bar() {
return new Bar(foo());
}
}
static class Foo {
public Foo() {
//System.out.println("created foo: " + this.getClass().getName());
}
public void doSomething() {
//System.out.println("interesting: " + this);
}
}
static class Bar {
private final Foo foo;
public Bar(Foo foo) {
this.foo = foo;
//System.out.println("created bar: " + this);
}
public Foo getFoo() {
return foo;
}
}
private void genericTestScope(String beanName) throws Exception {
String message = "scope is ignored";
Object bean1 = ctx.getBean(beanName);
Object bean2 = ctx.getBean(beanName);
assertSame(message, bean1, bean2);
Object bean3 = ctx.getBean(beanName);
assertSame(message, bean1, bean3);
// make the scope create a new object
customScope.createNewScope = true;
Object newBean1 = ctx.getBean(beanName);
assertNotSame(message, bean1, newBean1);
Object sameBean1 = ctx.getBean(beanName);
assertSame(message, newBean1, sameBean1);
// make the scope create a new object
customScope.createNewScope = true;
Object newBean2 = ctx.getBean(beanName);
assertNotSame(message, newBean1, newBean2);
// make the scope create a new object .. again
customScope.createNewScope = true;
Object newBean3 = ctx.getBean(beanName);
assertNotSame(message, newBean2, newBean3);
}
@Configuration
public static class InvalidProxyObjectConfiguration {
@ScopedProxy
public Object invalidProxyObject() { return new Object(); }
}
@Configuration
public static class InvalidProxyOnPredefinedScopesConfiguration {
@ScopedProxy @Bean
public Object invalidProxyOnPredefinedScopes() { return new Object(); }
}
@Configuration
public static class ScopedConfigurationClass {
@Bean(scope = SCOPE)
public TestBean scopedClass() {
TestBean tb = new TestBean();
tb.setName(flag);
return tb;
}
@Bean(scope = SCOPE)
public ITestBean scopedInterface() {
TestBean tb = new TestBean();
tb.setName(flag);
return tb;
}
@Bean(scope = SCOPE)
@ScopedProxy(proxyTargetClass = false)
public ITestBean scopedProxyInterface() {
TestBean tb = new TestBean();
tb.setName(flag);
return tb;
}
@ScopedProxy
@Bean(scope = SCOPE)
public TestBean scopedProxyClass() {
TestBean tb = new TestBean();
tb.setName(flag);
return tb;
}
@Bean
public TestBean singletonWithScopedClassDep() {
TestBean singleton = new TestBean();
singleton.setSpouse(scopedProxyClass());
return singleton;
}
@Bean
public TestBean singletonWithScopedInterfaceDep() {
TestBean singleton = new TestBean();
singleton.setSpouse(scopedProxyInterface());
return singleton;
}
}
}
Loading…
Cancel
Save