From 24e4f56d7efaafe72e672c8fc0d01d57150e6de3 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Wed, 25 Nov 2015 16:56:39 +0100 Subject: [PATCH] Test case for event listener methods on bean with potentially inactive scope Also taking the opportunity to refine the "No Scope registered" exception message a bit. Issue: SPR-13681 --- .../factory/support/AbstractBeanFactory.java | 6 +- .../AnnotationDrivenEventListenerTests.java | 93 +++++++++++++++++++ 2 files changed, 96 insertions(+), 3 deletions(-) diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java index edfd33d1081..73b897ebc27 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java @@ -334,7 +334,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp String scopeName = mbd.getScope(); final Scope scope = this.scopes.get(scopeName); if (scope == null) { - throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'"); + throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'"); } try { Object scopedInstance = scope.get(beanName, new ObjectFactory() { @@ -353,8 +353,8 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp } catch (IllegalStateException ex) { throw new BeanCreationException(beanName, - "Scope '" + scopeName + "' is not active for the current thread; " + - "consider defining a scoped proxy for this bean if you intend to refer to it from a singleton", + "Scope '" + scopeName + "' is not active for the current thread; consider " + + "defining a scoped proxy for this bean if you intend to refer to it from a singleton", ex); } } diff --git a/spring-context/src/test/java/org/springframework/context/event/AnnotationDrivenEventListenerTests.java b/spring-context/src/test/java/org/springframework/context/event/AnnotationDrivenEventListenerTests.java index c478c68aefa..7f40e7442c7 100644 --- a/spring-context/src/test/java/org/springframework/context/event/AnnotationDrivenEventListenerTests.java +++ b/spring-context/src/test/java/org/springframework/context/event/AnnotationDrivenEventListenerTests.java @@ -35,7 +35,9 @@ import org.junit.rules.ExpectedException; import org.springframework.aop.framework.Advised; import org.springframework.aop.support.AopUtils; +import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.BeanInitializationException; +import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.PayloadApplicationEvent; @@ -55,6 +57,7 @@ import org.springframework.core.annotation.Order; import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.stereotype.Component; +import org.springframework.util.Assert; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; @@ -238,6 +241,9 @@ public class AnnotationDrivenEventListenerTests { assertTrue("bean should be a proxy", proxy instanceof Advised); this.eventCollector.assertNoEventReceived(proxy.getId()); + this.context.publishEvent(new ContextRefreshedEvent(this.context)); + this.eventCollector.assertNoEventReceived(proxy.getId()); + TestEvent event = new TestEvent(); this.context.publishEvent(event); this.eventCollector.assertEvent(proxy.getId(), event); @@ -252,6 +258,9 @@ public class AnnotationDrivenEventListenerTests { assertTrue("bean should be a proxy", proxy instanceof Advised); this.eventCollector.assertNoEventReceived(proxy.getId()); + this.context.publishEvent(new ContextRefreshedEvent(this.context)); + this.eventCollector.assertNoEventReceived(proxy.getId()); + TestEvent event = new TestEvent(); this.context.publishEvent(event); this.eventCollector.assertEvent(proxy.getId(), event); @@ -266,12 +275,49 @@ public class AnnotationDrivenEventListenerTests { assertTrue("bean should be a cglib proxy", AopUtils.isCglibProxy(proxy)); this.eventCollector.assertNoEventReceived(proxy.getId()); + this.context.publishEvent(new ContextRefreshedEvent(this.context)); + this.eventCollector.assertNoEventReceived(proxy.getId()); + TestEvent event = new TestEvent(); this.context.publishEvent(event); this.eventCollector.assertEvent(proxy.getId(), event); this.eventCollector.assertTotalEventsCount(1); } + @Test + public void eventListenerWorksWithCustomScope() throws Exception { + load(CustomScopeTestBean.class); + CustomScope customScope = new CustomScope(); + this.context.getBeanFactory().registerScope("custom", customScope); + + CustomScopeTestBean proxy = this.context.getBean(CustomScopeTestBean.class); + assertTrue("bean should be a cglib proxy", AopUtils.isCglibProxy(proxy)); + this.eventCollector.assertNoEventReceived(proxy.getId()); + + this.context.publishEvent(new ContextRefreshedEvent(this.context)); + this.eventCollector.assertNoEventReceived(proxy.getId()); + + customScope.active = false; + this.context.publishEvent(new ContextRefreshedEvent(this.context)); + customScope.active = true; + this.eventCollector.assertNoEventReceived(proxy.getId()); + + TestEvent event = new TestEvent(); + this.context.publishEvent(event); + this.eventCollector.assertEvent(proxy.getId(), event); + this.eventCollector.assertTotalEventsCount(1); + + try { + customScope.active = false; + this.context.publishEvent(new TestEvent()); + fail("Should have thrown IllegalStateException"); + } + catch (BeanCreationException ex) { + // expected + assertTrue(ex.getCause() instanceof IllegalStateException); + } + } + @Test public void asyncProcessingApplied() throws InterruptedException { loadAsync(AsyncEventListener.class); @@ -724,6 +770,17 @@ public class AnnotationDrivenEventListenerTests { } + @Component + @Scope(scopeName = "custom", proxyMode = ScopedProxyMode.TARGET_CLASS) + static class CustomScopeTestBean extends AbstractTestEventListener { + + @EventListener + public void handleIt(TestEvent event) { + collectEvent(event); + } + } + + @Component static class GenericEventListener extends AbstractTestEventListener { @@ -779,4 +836,40 @@ public class AnnotationDrivenEventListenerTests { } } + + private static class CustomScope implements org.springframework.beans.factory.config.Scope { + + public boolean active = true; + + private Object instance = null; + + @Override + public Object get(String name, ObjectFactory objectFactory) { + Assert.state(this.active, "Not active"); + if (this.instance == null) { + this.instance = objectFactory.getObject(); + } + return this.instance; + } + + @Override + public Object remove(String name) { + return null; + } + + @Override + public void registerDestructionCallback(String name, Runnable callback) { + } + + @Override + public Object resolveContextualObject(String key) { + return null; + } + + @Override + public String getConversationId() { + return null; + } + } + }