11/*
2- * Copyright 2002-2014 the original author or authors.
2+ * Copyright 2002-2015 the original author or authors.
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
2525
2626import org .junit .Test ;
2727
28+ import org .springframework .aop .interceptor .AsyncUncaughtExceptionHandler ;
2829import org .springframework .aop .support .AopUtils ;
2930import org .springframework .beans .factory .config .BeanDefinition ;
3031import org .springframework .beans .factory .support .RootBeanDefinition ;
3132import org .springframework .context .ConfigurableApplicationContext ;
33+ import org .springframework .context .annotation .AnnotationConfigApplicationContext ;
34+ import org .springframework .context .annotation .Bean ;
35+ import org .springframework .context .annotation .Configuration ;
3236import org .springframework .context .support .GenericXmlApplicationContext ;
3337import org .springframework .context .support .StaticApplicationContext ;
3438import org .springframework .core .io .ClassPathResource ;
3539import org .springframework .scheduling .concurrent .ThreadPoolTaskExecutor ;
3640import org .springframework .util .ReflectionUtils ;
41+ import org .springframework .util .concurrent .ListenableFuture ;
3742
3843import static org .junit .Assert .*;
3944
@@ -106,10 +111,32 @@ public void configuredThroughNamespace() {
106111
107112 @ Test
108113 public void handleExceptionWithFuture () {
109- ConfigurableApplicationContext context = initContext (
110- new RootBeanDefinition ( AsyncAnnotationBeanPostProcessor .class ) );
114+ ConfigurableApplicationContext context =
115+ new AnnotationConfigApplicationContext ( ConfigWithExceptionHandler .class );
111116 ITestBean testBean = context .getBean ("target" , ITestBean .class );
112- final Future <Object > result = testBean .failWithFuture ();
117+
118+ TestableAsyncUncaughtExceptionHandler exceptionHandler =
119+ context .getBean ("exceptionHandler" , TestableAsyncUncaughtExceptionHandler .class );
120+ assertFalse ("handler should not have been called yet" , exceptionHandler .isCalled ());
121+ Future <Object > result = testBean .failWithFuture ();
122+ assertFutureWithException (result , exceptionHandler );
123+ }
124+
125+ @ Test
126+ public void handleExceptionWithListenableFuture () {
127+ ConfigurableApplicationContext context =
128+ new AnnotationConfigApplicationContext (ConfigWithExceptionHandler .class );
129+ ITestBean testBean = context .getBean ("target" , ITestBean .class );
130+
131+ TestableAsyncUncaughtExceptionHandler exceptionHandler =
132+ context .getBean ("exceptionHandler" , TestableAsyncUncaughtExceptionHandler .class );
133+ assertFalse ("handler should not have been called yet" , exceptionHandler .isCalled ());
134+ Future <Object > result = testBean .failWithListenableFuture ();
135+ assertFutureWithException (result , exceptionHandler );
136+ }
137+
138+ private void assertFutureWithException (Future <Object > result ,
139+ TestableAsyncUncaughtExceptionHandler exceptionHandler ) {
113140
114141 try {
115142 result .get ();
@@ -121,6 +148,7 @@ public void handleExceptionWithFuture() {
121148 // expected
122149 assertEquals ("Wrong exception cause" , UnsupportedOperationException .class , ex .getCause ().getClass ());
123150 }
151+ assertFalse ("handler should never be called with Future return type" , exceptionHandler .isCalled ());
124152 }
125153
126154 @ Test
@@ -173,14 +201,16 @@ private ConfigurableApplicationContext initContext(BeanDefinition asyncAnnotatio
173201 }
174202
175203
176- private static interface ITestBean {
204+ private interface ITestBean {
177205
178206 Thread getThread ();
179207
180208 void test ();
181209
182210 Future <Object > failWithFuture ();
183211
212+ ListenableFuture <Object > failWithListenableFuture ();
213+
184214 void failWithVoid ();
185215
186216 void await (long timeout );
@@ -206,11 +236,19 @@ public void test() {
206236 }
207237
208238 @ Async
239+ @ Override
209240 public Future <Object > failWithFuture () {
210241 throw new UnsupportedOperationException ("failWithFuture" );
211242 }
212243
213244 @ Async
245+ @ Override
246+ public ListenableFuture <Object > failWithListenableFuture () {
247+ throw new UnsupportedOperationException ("failWithListenableFuture" );
248+ }
249+
250+ @ Async
251+ @ Override
214252 public void failWithVoid () {
215253 throw new UnsupportedOperationException ("failWithVoid" );
216254 }
@@ -234,4 +272,25 @@ public void execute(Runnable r) {
234272 }
235273 }
236274
275+ @ Configuration
276+ @ EnableAsync
277+ static class ConfigWithExceptionHandler extends AsyncConfigurerSupport {
278+
279+ @ Bean
280+ public ITestBean target () {
281+ return new TestBean ();
282+ }
283+
284+ @ Override
285+ public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler () {
286+ return exceptionHandler ();
287+ }
288+
289+ @ Bean
290+ public TestableAsyncUncaughtExceptionHandler exceptionHandler () {
291+ return new TestableAsyncUncaughtExceptionHandler ();
292+ }
293+ }
294+
295+
237296}
0 commit comments