Skip to content

Commit 24e4f56

Browse files
committed
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
1 parent bb05bc7 commit 24e4f56

File tree

2 files changed

+96
-3
lines changed

2 files changed

+96
-3
lines changed

spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ else if (mbd.isPrototype()) {
334334
String scopeName = mbd.getScope();
335335
final Scope scope = this.scopes.get(scopeName);
336336
if (scope == null) {
337-
throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
337+
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
338338
}
339339
try {
340340
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
@@ -353,8 +353,8 @@ public Object getObject() throws BeansException {
353353
}
354354
catch (IllegalStateException ex) {
355355
throw new BeanCreationException(beanName,
356-
"Scope '" + scopeName + "' is not active for the current thread; " +
357-
"consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",
356+
"Scope '" + scopeName + "' is not active for the current thread; consider " +
357+
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
358358
ex);
359359
}
360360
}

spring-context/src/test/java/org/springframework/context/event/AnnotationDrivenEventListenerTests.java

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@
3535

3636
import org.springframework.aop.framework.Advised;
3737
import org.springframework.aop.support.AopUtils;
38+
import org.springframework.beans.factory.BeanCreationException;
3839
import org.springframework.beans.factory.BeanInitializationException;
40+
import org.springframework.beans.factory.ObjectFactory;
3941
import org.springframework.beans.factory.annotation.Autowired;
4042
import org.springframework.context.ConfigurableApplicationContext;
4143
import org.springframework.context.PayloadApplicationEvent;
@@ -55,6 +57,7 @@
5557
import org.springframework.scheduling.annotation.Async;
5658
import org.springframework.scheduling.annotation.EnableAsync;
5759
import org.springframework.stereotype.Component;
60+
import org.springframework.util.Assert;
5861

5962
import static org.hamcrest.Matchers.*;
6063
import static org.junit.Assert.*;
@@ -238,6 +241,9 @@ public void eventListenerWorksWithSimpleInterfaceProxy() throws Exception {
238241
assertTrue("bean should be a proxy", proxy instanceof Advised);
239242
this.eventCollector.assertNoEventReceived(proxy.getId());
240243

244+
this.context.publishEvent(new ContextRefreshedEvent(this.context));
245+
this.eventCollector.assertNoEventReceived(proxy.getId());
246+
241247
TestEvent event = new TestEvent();
242248
this.context.publishEvent(event);
243249
this.eventCollector.assertEvent(proxy.getId(), event);
@@ -252,6 +258,9 @@ public void eventListenerWorksWithAnnotatedInterfaceProxy() throws Exception {
252258
assertTrue("bean should be a proxy", proxy instanceof Advised);
253259
this.eventCollector.assertNoEventReceived(proxy.getId());
254260

261+
this.context.publishEvent(new ContextRefreshedEvent(this.context));
262+
this.eventCollector.assertNoEventReceived(proxy.getId());
263+
255264
TestEvent event = new TestEvent();
256265
this.context.publishEvent(event);
257266
this.eventCollector.assertEvent(proxy.getId(), event);
@@ -266,10 +275,47 @@ public void eventListenerWorksWithCglibProxy() throws Exception {
266275
assertTrue("bean should be a cglib proxy", AopUtils.isCglibProxy(proxy));
267276
this.eventCollector.assertNoEventReceived(proxy.getId());
268277

278+
this.context.publishEvent(new ContextRefreshedEvent(this.context));
279+
this.eventCollector.assertNoEventReceived(proxy.getId());
280+
281+
TestEvent event = new TestEvent();
282+
this.context.publishEvent(event);
283+
this.eventCollector.assertEvent(proxy.getId(), event);
284+
this.eventCollector.assertTotalEventsCount(1);
285+
}
286+
287+
@Test
288+
public void eventListenerWorksWithCustomScope() throws Exception {
289+
load(CustomScopeTestBean.class);
290+
CustomScope customScope = new CustomScope();
291+
this.context.getBeanFactory().registerScope("custom", customScope);
292+
293+
CustomScopeTestBean proxy = this.context.getBean(CustomScopeTestBean.class);
294+
assertTrue("bean should be a cglib proxy", AopUtils.isCglibProxy(proxy));
295+
this.eventCollector.assertNoEventReceived(proxy.getId());
296+
297+
this.context.publishEvent(new ContextRefreshedEvent(this.context));
298+
this.eventCollector.assertNoEventReceived(proxy.getId());
299+
300+
customScope.active = false;
301+
this.context.publishEvent(new ContextRefreshedEvent(this.context));
302+
customScope.active = true;
303+
this.eventCollector.assertNoEventReceived(proxy.getId());
304+
269305
TestEvent event = new TestEvent();
270306
this.context.publishEvent(event);
271307
this.eventCollector.assertEvent(proxy.getId(), event);
272308
this.eventCollector.assertTotalEventsCount(1);
309+
310+
try {
311+
customScope.active = false;
312+
this.context.publishEvent(new TestEvent());
313+
fail("Should have thrown IllegalStateException");
314+
}
315+
catch (BeanCreationException ex) {
316+
// expected
317+
assertTrue(ex.getCause() instanceof IllegalStateException);
318+
}
273319
}
274320

275321
@Test
@@ -724,6 +770,17 @@ public void handleIt(TestEvent event) {
724770
}
725771

726772

773+
@Component
774+
@Scope(scopeName = "custom", proxyMode = ScopedProxyMode.TARGET_CLASS)
775+
static class CustomScopeTestBean extends AbstractTestEventListener {
776+
777+
@EventListener
778+
public void handleIt(TestEvent event) {
779+
collectEvent(event);
780+
}
781+
}
782+
783+
727784
@Component
728785
static class GenericEventListener extends AbstractTestEventListener {
729786

@@ -779,4 +836,40 @@ public void handleSecond(String payload) {
779836
}
780837
}
781838

839+
840+
private static class CustomScope implements org.springframework.beans.factory.config.Scope {
841+
842+
public boolean active = true;
843+
844+
private Object instance = null;
845+
846+
@Override
847+
public Object get(String name, ObjectFactory<?> objectFactory) {
848+
Assert.state(this.active, "Not active");
849+
if (this.instance == null) {
850+
this.instance = objectFactory.getObject();
851+
}
852+
return this.instance;
853+
}
854+
855+
@Override
856+
public Object remove(String name) {
857+
return null;
858+
}
859+
860+
@Override
861+
public void registerDestructionCallback(String name, Runnable callback) {
862+
}
863+
864+
@Override
865+
public Object resolveContextualObject(String key) {
866+
return null;
867+
}
868+
869+
@Override
870+
public String getConversationId() {
871+
return null;
872+
}
873+
}
874+
782875
}

0 commit comments

Comments
 (0)