diff --git a/spring-web/src/main/java/org/springframework/web/context/request/async/CallableInterceptorChain.java b/spring-web/src/main/java/org/springframework/web/context/request/async/CallableInterceptorChain.java index a79a5a34c7..e0e5e6fb0c 100644 --- a/spring-web/src/main/java/org/springframework/web/context/request/async/CallableInterceptorChain.java +++ b/spring-web/src/main/java/org/springframework/web/context/request/async/CallableInterceptorChain.java @@ -49,15 +49,22 @@ class CallableInterceptorChain { } public Object applyPostProcess(NativeWebRequest request, Callable task, Object concurrentResult) { + Throwable exceptionResult = null; for (int i = this.preProcessIndex; i >= 0; i--) { try { this.interceptors.get(i).postProcess(request, task, concurrentResult); } catch (Throwable t) { - return t; + // Save the first exception but invoke all interceptors + if (exceptionResult != null) { + logger.error("postProcess error", t); + } + else { + exceptionResult = t; + } } } - return concurrentResult; + return (exceptionResult != null) ? exceptionResult : concurrentResult; } public Object triggerAfterTimeout(NativeWebRequest request, Callable task) { diff --git a/spring-web/src/main/java/org/springframework/web/context/request/async/WebAsyncManager.java b/spring-web/src/main/java/org/springframework/web/context/request/async/WebAsyncManager.java index add36ba721..381782153d 100644 --- a/spring-web/src/main/java/org/springframework/web/context/request/async/WebAsyncManager.java +++ b/spring-web/src/main/java/org/springframework/web/context/request/async/WebAsyncManager.java @@ -197,7 +197,7 @@ public final class WebAsyncManager { * The key is derived from the class name and hashcode. * @param interceptor the interceptor to register */ - public void registerCallableInterceptor(CallableProcessingInterceptor... interceptors) { + public void registerCallableInterceptors(CallableProcessingInterceptor... interceptors) { Assert.notNull(interceptors, "A CallableProcessingInterceptor is required"); for (CallableProcessingInterceptor interceptor : interceptors) { String key = interceptor.getClass().getName() + ":" + interceptor.hashCode(); @@ -222,7 +222,7 @@ public final class WebAsyncManager { * @param key the key * @param interceptors the interceptor to register */ - public void registerDeferredResultInterceptor(DeferredResultProcessingInterceptor... interceptors) { + public void registerDeferredResultInterceptors(DeferredResultProcessingInterceptor... interceptors) { Assert.notNull(interceptors, "A DeferredResultProcessingInterceptor is required"); for (DeferredResultProcessingInterceptor interceptor : interceptors) { String key = interceptors.getClass().getName() + ":" + interceptors.hashCode(); diff --git a/spring-web/src/test/java/org/springframework/web/context/request/async/WebAsyncManagerTests.java b/spring-web/src/test/java/org/springframework/web/context/request/async/WebAsyncManagerTests.java index a4e5a334a9..11891cfa01 100644 --- a/spring-web/src/test/java/org/springframework/web/context/request/async/WebAsyncManagerTests.java +++ b/spring-web/src/test/java/org/springframework/web/context/request/async/WebAsyncManagerTests.java @@ -200,6 +200,36 @@ public class WebAsyncManagerTests { verify(interceptor, this.asyncWebRequest); } + @Test + public void startCallableProcessingPostProcessContinueAfterException() throws Exception { + + Callable task = new StubCallable(21); + Exception exception = new Exception(); + + CallableProcessingInterceptor interceptor1 = createMock(CallableProcessingInterceptor.class); + interceptor1.preProcess(this.asyncWebRequest, task); + interceptor1.postProcess(this.asyncWebRequest, task, 21); + replay(interceptor1); + + CallableProcessingInterceptor interceptor2 = createMock(CallableProcessingInterceptor.class); + interceptor2.preProcess(this.asyncWebRequest, task); + interceptor2.postProcess(this.asyncWebRequest, task, 21); + expectLastCall().andThrow(exception); + replay(interceptor2); + + setupDefaultAsyncScenario(); + + this.asyncManager.registerCallableInterceptors(interceptor1, interceptor2); + this.asyncManager.startCallableProcessing(task); + + assertTrue(this.asyncManager.hasConcurrentResult()); + assertEquals(exception, this.asyncManager.getConcurrentResult()); + + verify(interceptor1); + verify(interceptor2); + verify(this.asyncWebRequest); + } + @Test public void startCallableProcessingWithAsyncTask() { diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java index 60223265d5..ad9279328e 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java @@ -728,8 +728,8 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i final WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); asyncManager.setTaskExecutor(this.taskExecutor); asyncManager.setAsyncWebRequest(asyncWebRequest); - asyncManager.registerCallableInterceptor(this.callableInterceptors); - asyncManager.registerDeferredResultInterceptor(this.deferredResultInterceptors); + asyncManager.registerCallableInterceptors(this.callableInterceptors); + asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors); if (asyncManager.hasConcurrentResult()) { Object result = asyncManager.getConcurrentResult();