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; @@ -57,6 +57,7 @@ import org.springframework.beans.factory.support.AbstractBeanDefinition;
* @author Rod Johnson
* @author Costin Leau
* @author Chris Beams
* @since 3.0
*/
@Target(ElementType.METHOD)
@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; @@ -25,7 +25,6 @@ import java.util.List;
import org.springframework.util.Assert;
/** TODO: JAVADOC */
public final class BeanMethod implements Validatable {
private final String name;
@ -91,8 +90,8 @@ public final class BeanMethod implements Validatable { @@ -91,8 +90,8 @@ public final class BeanMethod implements Validatable {
T anno = getAnnotation(annoType);
if (anno == null)
throw new IllegalStateException(format("annotation %s not found on %s", annoType.getSimpleName(),
this));
throw new IllegalStateException(
format("annotation %s not found on %s", annoType.getSimpleName(), this));
return anno;
}
@ -123,8 +122,6 @@ public final class BeanMethod implements Validatable { @@ -123,8 +122,6 @@ public final class BeanMethod implements Validatable {
}
public void validate(List<UsageError> errors) {
// for (Validator validator : validators)
// validator.validate(this, errors);
if (Modifier.isPrivate(getModifiers()))
errors.add(new PrivateMethodError());
@ -163,7 +160,7 @@ public final class BeanMethod implements Validatable { @@ -163,7 +160,7 @@ public final class BeanMethod implements Validatable {
public String toString() {
String returnTypeName = returnType == null ? "<unknown>" : returnType.getSimpleName();
return String.format("%s: name=%s; returnType=%s; modifiers=%d", getClass().getSimpleName(), name,
returnTypeName, modifiers);
returnTypeName, modifiers);
}
@Override
@ -246,15 +243,14 @@ class BeanValidator implements Validator { @@ -246,15 +243,14 @@ class BeanValidator implements Validator {
public void validate(Object object, List<UsageError> errors) {
BeanMethod method = (BeanMethod) object;
// TODO: re-enable for @ScopedProxy support
// if (method.getAnnotation(ScopedProxy.class) == null)
// return;
//
// Bean bean = method.getRequiredAnnotation(Bean.class);
//
// if (bean.scope().equals(DefaultScopes.SINGLETON)
// || bean.scope().equals(DefaultScopes.PROTOTYPE))
// errors.add(new InvalidScopedProxyDeclarationError(method));
if (method.getAnnotation(ScopedProxy.class) == null)
return;
Bean bean = method.getRequiredAnnotation(Bean.class);
if (bean.scope().equals(StandardScopes.SINGLETON)
|| bean.scope().equals(StandardScopes.PROTOTYPE))
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; @@ -7,6 +7,8 @@ import java.lang.reflect.Method;
import org.apache.commons.logging.Log;
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.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
@ -50,7 +52,7 @@ public class BeanRegistrar implements BeanDefinitionRegistrar { @@ -50,7 +52,7 @@ public class BeanRegistrar implements BeanDefinitionRegistrar {
if (bean.autowire() != AnnotationUtils.getDefaultValue(Bean.class, "autowire"))
beanDef.setAutowireMode(bean.autowire().value());
else if (defaults.defaultAutowire() != AnnotationUtils.getDefaultValue(Configuration.class,
"defaultAutowire"))
"defaultAutowire"))
beanDef.setAutowireMode(defaults.defaultAutowire().value());
String beanName = method.getName();
@ -70,9 +72,8 @@ public class BeanRegistrar implements BeanDefinitionRegistrar { @@ -70,9 +72,8 @@ public class BeanRegistrar implements BeanDefinitionRegistrar {
}
// overriding is legal, return immediately
logger.info(format(
"Skipping loading bean definition for %s: a definition for bean '%s' already exists. "
+ "This is likely due to an override in XML.", method, beanName));
logger.info(format("Skipping loading bean definition for %s: a definition for bean "
+ "'%s' already exists. This is likely due to an override in XML.", method, beanName));
return;
}
}
@ -104,39 +105,33 @@ public class BeanRegistrar implements BeanDefinitionRegistrar { @@ -104,39 +105,33 @@ public class BeanRegistrar implements BeanDefinitionRegistrar {
if (hasText(destroyMethodName))
beanDef.setDestroyMethodName(destroyMethodName);
// TODO: re-enable for @ScopedProxy support
// is this method annotated with @ScopedProxy?
// ScopedProxy scopedProxy = method.getAnnotation(ScopedProxy.class);
// if (scopedProxy != null) {
// RootBeanDefinition targetDef = beanDef;
//
// // Create a scoped proxy definition for the original bean name,
// // "hiding" the target bean in an internal target definition.
// String targetBeanName =
// ScopedProxy.Util.resolveHiddenScopedProxyBeanName(beanName);
// RootBeanDefinition scopedProxyDefinition = new
// RootBeanDefinition(ScopedProxyFactoryBean.class);
// scopedProxyDefinition.getPropertyValues().addPropertyValue("targetBeanName",
// targetBeanName);
//
// if (scopedProxy.proxyTargetClass())
// targetDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE,
// Boolean.TRUE);
// // ScopedFactoryBean's "proxyTargetClass" default is TRUE, so we
// // don't need to set it explicitly here.
// else
// scopedProxyDefinition.getPropertyValues().addPropertyValue("proxyTargetClass",
// Boolean.FALSE);
//
// // The target bean should be ignored in favor of the scoped proxy.
// targetDef.setAutowireCandidate(false);
//
// // 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;
// }
ScopedProxy scopedProxy = method.getAnnotation(ScopedProxy.class);
if (scopedProxy != null) {
RootBeanDefinition targetDef = beanDef;
//
// Create a scoped proxy definition for the original bean name,
// "hiding" the target bean in an internal target definition.
String targetBeanName = ScopedProxy.Util.resolveHiddenScopedProxyBeanName(beanName);
RootBeanDefinition scopedProxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);
scopedProxyDefinition.getPropertyValues().addPropertyValue("targetBeanName", targetBeanName);
if (scopedProxy.proxyTargetClass())
targetDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
// ScopedFactoryBean's "proxyTargetClass" default is TRUE, so we
// don't need to set it explicitly here.
else
scopedProxyDefinition.getPropertyValues().addPropertyValue("proxyTargetClass", Boolean.FALSE);
// The target bean should be ignored in favor of the scoped proxy.
targetDef.setAutowireCandidate(false);
// 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
// does this bean method have any @Meta annotations?
@ -147,8 +142,8 @@ public class BeanRegistrar implements BeanDefinitionRegistrar { @@ -147,8 +142,8 @@ public class BeanRegistrar implements BeanDefinitionRegistrar {
if (bean.dependsOn().length > 0)
beanDef.setDependsOn(bean.dependsOn());
logger.info(format("Registering bean definition for @Bean method %s.%s()", configClass.getName(),
beanName));
logger.info(format("Registering bean definition for @Bean method %s.%s()",
configClass.getName(), beanName));
registry.registerBeanDefinition(beanName, beanDef);
@ -188,7 +183,7 @@ public class BeanRegistrar implements BeanDefinitionRegistrar { @@ -188,7 +183,7 @@ public class BeanRegistrar implements BeanDefinitionRegistrar {
} while (clbf != null);
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 { @@ -201,4 +196,4 @@ public class BeanRegistrar implements BeanDefinitionRegistrar {
*/
@SuppressWarnings("serial")
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; @@ -46,6 +46,7 @@ import org.springframework.stereotype.Component;
*
* @author Rod Johnson
* @author Chris Beams
* @since 3.0
*/
@Component
@Target( { ElementType.TYPE })

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

@ -0,0 +1,33 @@ @@ -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 @@ @@ -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; @@ -24,6 +24,8 @@ import net.sf.cglib.proxy.MethodProxy;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.config.java.Bean;
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 { @@ -44,14 +46,13 @@ class BeanMethodInterceptor extends AbstractMethodInterceptor {
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
String beanName = getBeanName(method);
// TODO: re-enable for @ScopedProxy support
// boolean isScopedProxy = (AnnotationUtils.findAnnotation(method,
// ScopedProxy.class) != null);
//
// String scopedBeanName =
// ScopedProxy.Util.resolveHiddenScopedProxyBeanName(beanName);
// if (isScopedProxy && beanFactory.isCurrentlyInCreation(scopedBeanName))
// beanName = scopedBeanName;
boolean isScopedProxy =
(AnnotationUtils.findAnnotation(method, ScopedProxy.class) != null);
String scopedBeanName =
ScopedProxy.Util.resolveHiddenScopedProxyBeanName(beanName);
if (isScopedProxy && beanFactory.isCurrentlyInCreation(scopedBeanName))
beanName = scopedBeanName;
if (factoryContainsBean(beanName)) {
// 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 { @@ -110,7 +110,7 @@ public class ConfigurationPostProcessorTests {
* certain bean semantics, like singleton-scoping, scoped proxies, etc.
*
* 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.
* We test for such a case below, and in doing so prove that enhancement is
* working.
@ -142,5 +142,5 @@ public class ConfigurationPostProcessorTests { @@ -142,5 +142,5 @@ public class ConfigurationPostProcessorTests {
final 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 @@ @@ -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 @@ @@ -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