Add AsyncHandlerMethodReturnValueHandler

Before this change HandlerMethodReturnValueHandler's were invoked in a
specific order (type-based, annotation-based, custom). However handlers
that deal with asynchronous return value handling need to always be
considered first. This affects custom handlers in particular since they
are normally ordered last.

This change introduces an AsyncHandlerMethodReturnValueHandler
sub-interface with a single method to determine if the return value is
asynchronous and if it is to look for a matching handler only among
those that are of type AsyncHandlerMethodReturnValueHandler.

Issue: SPR-13083
This commit is contained in:
Rossen Stoyanchev
2015-06-16 08:40:46 -04:00
parent 8187833502
commit 210e10c657
10 changed files with 204 additions and 110 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -21,7 +21,7 @@ import org.springframework.core.MethodParameter;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.async.WebAsyncTask;
import org.springframework.web.context.request.async.WebAsyncUtils;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.AsyncHandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;
/**
@@ -30,7 +30,7 @@ import org.springframework.web.method.support.ModelAndViewContainer;
* @author Rossen Stoyanchev
* @since 3.2
*/
public class AsyncTaskMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
public class AsyncTaskMethodReturnValueHandler implements AsyncHandlerMethodReturnValueHandler {
private final BeanFactory beanFactory;
@@ -45,6 +45,11 @@ public class AsyncTaskMethodReturnValueHandler implements HandlerMethodReturnVal
return WebAsyncTask.class.isAssignableFrom(returnType.getParameterType());
}
@Override
public boolean isAsyncReturnValue(Object returnValue, MethodParameter returnType) {
return (returnValue != null && returnValue instanceof WebAsyncTask);
}
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -21,6 +21,7 @@ import java.util.concurrent.Callable;
import org.springframework.core.MethodParameter;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.async.WebAsyncUtils;
import org.springframework.web.method.support.AsyncHandlerMethodReturnValueHandler;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;
@@ -30,13 +31,18 @@ import org.springframework.web.method.support.ModelAndViewContainer;
* @author Rossen Stoyanchev
* @since 3.2
*/
public class CallableMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
public class CallableMethodReturnValueHandler implements AsyncHandlerMethodReturnValueHandler {
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return Callable.class.isAssignableFrom(returnType.getParameterType());
}
@Override
public boolean isAsyncReturnValue(Object returnValue, MethodParameter returnType) {
return (returnValue != null && returnValue instanceof Callable);
}
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

View File

@@ -25,7 +25,7 @@ import org.springframework.lang.UsesJava8;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.async.DeferredResult;
import org.springframework.web.context.request.async.WebAsyncUtils;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.AsyncHandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;
/**
@@ -36,13 +36,18 @@ import org.springframework.web.method.support.ModelAndViewContainer;
* @since 4.2
*/
@UsesJava8
public class CompletionStageReturnValueHandler implements HandlerMethodReturnValueHandler {
public class CompletionStageReturnValueHandler implements AsyncHandlerMethodReturnValueHandler {
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return CompletionStage.class.isAssignableFrom(returnType.getParameterType());
}
@Override
public boolean isAsyncReturnValue(Object returnValue, MethodParameter returnType) {
return (returnValue != null && returnValue instanceof CompletionStage);
}
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
@@ -70,7 +75,6 @@ public class CompletionStageReturnValueHandler implements HandlerMethodReturnVal
return null;
}
});
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -20,6 +20,7 @@ import org.springframework.core.MethodParameter;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.async.DeferredResult;
import org.springframework.web.context.request.async.WebAsyncUtils;
import org.springframework.web.method.support.AsyncHandlerMethodReturnValueHandler;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;
@@ -29,13 +30,18 @@ import org.springframework.web.method.support.ModelAndViewContainer;
* @author Rossen Stoyanchev
* @since 3.2
*/
public class DeferredResultMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
public class DeferredResultMethodReturnValueHandler implements AsyncHandlerMethodReturnValueHandler {
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return DeferredResult.class.isAssignableFrom(returnType.getParameterType());
}
@Override
public boolean isAsyncReturnValue(Object returnValue, MethodParameter returnType) {
return (returnValue != null && returnValue instanceof DeferredResult);
}
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@@ -22,7 +22,7 @@ import org.springframework.util.concurrent.ListenableFutureCallback;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.async.DeferredResult;
import org.springframework.web.context.request.async.WebAsyncUtils;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.AsyncHandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;
/**
@@ -32,13 +32,18 @@ import org.springframework.web.method.support.ModelAndViewContainer;
* @author Rossen Stoyanchev
* @since 4.1
*/
public class ListenableFutureReturnValueHandler implements HandlerMethodReturnValueHandler {
public class ListenableFutureReturnValueHandler implements AsyncHandlerMethodReturnValueHandler {
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return ListenableFuture.class.isAssignableFrom(returnType.getParameterType());
}
@Override
public boolean isAsyncReturnValue(Object returnValue, MethodParameter returnType) {
return (returnValue != null && returnValue instanceof ListenableFuture);
}
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

View File

@@ -40,7 +40,7 @@ import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.async.DeferredResult;
import org.springframework.web.context.request.async.WebAsyncUtils;
import org.springframework.web.filter.ShallowEtagHeaderFilter;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.AsyncHandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;
/**
@@ -50,7 +50,7 @@ import org.springframework.web.method.support.ModelAndViewContainer;
* @author Rossen Stoyanchev
* @since 4.2
*/
public class ResponseBodyEmitterReturnValueHandler implements HandlerMethodReturnValueHandler {
public class ResponseBodyEmitterReturnValueHandler implements AsyncHandlerMethodReturnValueHandler {
private static final Log logger = LogFactory.getLog(ResponseBodyEmitterReturnValueHandler.class);
@@ -75,6 +75,20 @@ public class ResponseBodyEmitterReturnValueHandler implements HandlerMethodRetur
return false;
}
@Override
public boolean isAsyncReturnValue(Object returnValue, MethodParameter returnType) {
if (returnValue != null) {
if (returnValue instanceof ResponseBodyEmitter) {
return true;
}
else if (returnValue instanceof ResponseEntity) {
Object body = ((ResponseEntity) returnValue).getBody();
return (body != null && body instanceof ResponseBodyEmitter);
}
}
return false;
}
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {