Support for Servlet 4.0 (PushBuilder argument, MockServletContext)
Issue: SPR-12674
This commit is contained in:
@@ -16,8 +16,10 @@
|
||||
|
||||
package org.springframework.web.servlet.mvc.method.annotation;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.lang.reflect.Method;
|
||||
import java.security.Principal;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Locale;
|
||||
@@ -28,6 +30,8 @@ import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.web.bind.support.WebDataBinderFactory;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
@@ -43,13 +47,14 @@ import org.springframework.web.servlet.support.RequestContextUtils;
|
||||
* <li>{@link ServletRequest}
|
||||
* <li>{@link MultipartRequest}
|
||||
* <li>{@link HttpSession}
|
||||
* <li>{@link PushBuilder} (as of Spring 5.0 on Servlet 4.0)
|
||||
* <li>{@link Principal}
|
||||
* <li>{@link InputStream}
|
||||
* <li>{@link Reader}
|
||||
* <li>{@link HttpMethod} (as of Spring 4.0)</li>
|
||||
* <li>{@link HttpMethod} (as of Spring 4.0)
|
||||
* <li>{@link Locale}
|
||||
* <li>{@link TimeZone} (as of Spring 4.0)
|
||||
* <li>{@link java.time.ZoneId} (as of Spring 4.0 and Java 8)</li>
|
||||
* <li>{@link java.time.ZoneId} (as of Spring 4.0 and Java 8)
|
||||
* </ul>
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
@@ -59,6 +64,10 @@ import org.springframework.web.servlet.support.RequestContextUtils;
|
||||
*/
|
||||
public class ServletRequestMethodArgumentResolver implements HandlerMethodArgumentResolver {
|
||||
|
||||
private static final Method getPushBuilderMethod =
|
||||
ClassUtils.getMethodIfAvailable(HttpServletRequest.class, "getPushBuilder");
|
||||
|
||||
|
||||
@Override
|
||||
public boolean supportsParameter(MethodParameter parameter) {
|
||||
Class<?> paramType = parameter.getParameterType();
|
||||
@@ -66,6 +75,7 @@ public class ServletRequestMethodArgumentResolver implements HandlerMethodArgume
|
||||
ServletRequest.class.isAssignableFrom(paramType) ||
|
||||
MultipartRequest.class.isAssignableFrom(paramType) ||
|
||||
HttpSession.class.isAssignableFrom(paramType) ||
|
||||
(getPushBuilderMethod != null && getPushBuilderMethod.getReturnType().isAssignableFrom(paramType)) ||
|
||||
Principal.class.isAssignableFrom(paramType) ||
|
||||
InputStream.class.isAssignableFrom(paramType) ||
|
||||
Reader.class.isAssignableFrom(paramType) ||
|
||||
@@ -80,6 +90,8 @@ public class ServletRequestMethodArgumentResolver implements HandlerMethodArgume
|
||||
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
|
||||
|
||||
Class<?> paramType = parameter.getParameterType();
|
||||
|
||||
// WebRequest / NativeWebRequest / ServletWebRequest
|
||||
if (WebRequest.class.isAssignableFrom(paramType)) {
|
||||
if (!paramType.isInstance(webRequest)) {
|
||||
throw new IllegalStateException(
|
||||
@@ -88,16 +100,26 @@ public class ServletRequestMethodArgumentResolver implements HandlerMethodArgume
|
||||
return webRequest;
|
||||
}
|
||||
|
||||
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
|
||||
// ServletRequest / HttpServletRequest / MultipartRequest / MultipartHttpServletRequest
|
||||
if (ServletRequest.class.isAssignableFrom(paramType) || MultipartRequest.class.isAssignableFrom(paramType)) {
|
||||
Object nativeRequest = webRequest.getNativeRequest(paramType);
|
||||
if (nativeRequest == null) {
|
||||
throw new IllegalStateException(
|
||||
"Current request is not of type [" + paramType.getName() + "]: " + request);
|
||||
}
|
||||
return nativeRequest;
|
||||
return resolveNativeRequest(webRequest, paramType);
|
||||
}
|
||||
else if (HttpSession.class.isAssignableFrom(paramType)) {
|
||||
|
||||
// HttpServletRequest required for all further argument types
|
||||
return resolveArgument(paramType, resolveNativeRequest(webRequest, HttpServletRequest.class));
|
||||
}
|
||||
|
||||
private <T> T resolveNativeRequest(NativeWebRequest webRequest, Class<T> requiredType) {
|
||||
T nativeRequest = webRequest.getNativeRequest(requiredType);
|
||||
if (nativeRequest == null) {
|
||||
throw new IllegalStateException(
|
||||
"Current request is not of type [" + requiredType.getName() + "]: " + webRequest);
|
||||
}
|
||||
return nativeRequest;
|
||||
}
|
||||
|
||||
private Object resolveArgument(Class<?> paramType, HttpServletRequest request) throws IOException {
|
||||
if (HttpSession.class.isAssignableFrom(paramType)) {
|
||||
HttpSession session = request.getSession();
|
||||
if (!paramType.isInstance(session)) {
|
||||
throw new IllegalStateException(
|
||||
@@ -105,6 +127,14 @@ public class ServletRequestMethodArgumentResolver implements HandlerMethodArgume
|
||||
}
|
||||
return session;
|
||||
}
|
||||
else if (getPushBuilderMethod != null && getPushBuilderMethod.getReturnType().isAssignableFrom(paramType)) {
|
||||
Object pushBuilder = ReflectionUtils.invokeMethod(getPushBuilderMethod, request);
|
||||
if (!paramType.isInstance(pushBuilder)) {
|
||||
throw new IllegalStateException(
|
||||
"Current push builder is not of type [" + paramType.getName() + "]: " + pushBuilder);
|
||||
}
|
||||
return pushBuilder;
|
||||
}
|
||||
else if (InputStream.class.isAssignableFrom(paramType)) {
|
||||
InputStream inputStream = request.getInputStream();
|
||||
if (!paramType.isInstance(inputStream)) {
|
||||
@@ -143,11 +173,9 @@ public class ServletRequestMethodArgumentResolver implements HandlerMethodArgume
|
||||
TimeZone timeZone = RequestContextUtils.getTimeZone(request);
|
||||
return (timeZone != null ? timeZone.toZoneId() : ZoneId.systemDefault());
|
||||
}
|
||||
else {
|
||||
// Should never happen...
|
||||
throw new UnsupportedOperationException(
|
||||
"Unknown parameter type [" + paramType.getName() + "] in " + parameter.getMethod());
|
||||
}
|
||||
|
||||
// Should never happen...
|
||||
throw new UnsupportedOperationException("Unknown parameter type: " + paramType.getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -16,11 +16,10 @@
|
||||
|
||||
package org.springframework.web.servlet.mvc.method.annotation;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.Method;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.web.bind.support.WebDataBinderFactory;
|
||||
@@ -38,6 +37,7 @@ import org.springframework.web.method.support.ModelAndViewContainer;
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
public class ServletResponseMethodArgumentResolver implements HandlerMethodArgumentResolver {
|
||||
@@ -64,28 +64,36 @@ public class ServletResponseMethodArgumentResolver implements HandlerMethodArgum
|
||||
mavContainer.setRequestHandled(true);
|
||||
}
|
||||
|
||||
HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
|
||||
Class<?> paramType = parameter.getParameterType();
|
||||
|
||||
// ServletResponse, HttpServletResponse
|
||||
if (ServletResponse.class.isAssignableFrom(paramType)) {
|
||||
Object nativeResponse = webRequest.getNativeResponse(paramType);
|
||||
if (nativeResponse == null) {
|
||||
throw new IllegalStateException(
|
||||
"Current response is not of type [" + paramType.getName() + "]: " + response);
|
||||
}
|
||||
return nativeResponse;
|
||||
return resolveNativeResponse(webRequest, paramType);
|
||||
}
|
||||
else if (OutputStream.class.isAssignableFrom(paramType)) {
|
||||
|
||||
// ServletResponse required for all further argument types
|
||||
return resolveArgument(paramType, resolveNativeResponse(webRequest, ServletResponse.class));
|
||||
}
|
||||
|
||||
private <T> T resolveNativeResponse(NativeWebRequest webRequest, Class<T> requiredType) {
|
||||
T nativeResponse = webRequest.getNativeResponse(requiredType);
|
||||
if (nativeResponse == null) {
|
||||
throw new IllegalStateException(
|
||||
"Current response is not of type [" + requiredType.getName() + "]: " + webRequest);
|
||||
}
|
||||
return nativeResponse;
|
||||
}
|
||||
|
||||
private Object resolveArgument(Class<?> paramType, ServletResponse response) throws IOException {
|
||||
if (OutputStream.class.isAssignableFrom(paramType)) {
|
||||
return response.getOutputStream();
|
||||
}
|
||||
else if (Writer.class.isAssignableFrom(paramType)) {
|
||||
return response.getWriter();
|
||||
}
|
||||
else {
|
||||
// should not happen
|
||||
Method method = parameter.getMethod();
|
||||
throw new UnsupportedOperationException("Unknown parameter type: " + paramType + " in method: " + method);
|
||||
}
|
||||
|
||||
// Should never happen...
|
||||
throw new UnsupportedOperationException("Unknown parameter type: " + paramType);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -75,11 +75,9 @@ public class ServletRequestMethodArgumentResolverTests {
|
||||
@Test
|
||||
public void servletRequest() throws Exception {
|
||||
MethodParameter servletRequestParameter = new MethodParameter(method, 0);
|
||||
assertTrue("ServletRequest not supported", resolver.supportsParameter(servletRequestParameter));
|
||||
|
||||
boolean isSupported = resolver.supportsParameter(servletRequestParameter);
|
||||
Object result = resolver.resolveArgument(servletRequestParameter, mavContainer, webRequest, null);
|
||||
|
||||
assertTrue("ServletRequest not supported", isSupported);
|
||||
assertSame("Invalid result", servletRequest, result);
|
||||
assertFalse("The requestHandled flag shouldn't change", mavContainer.isRequestHandled());
|
||||
}
|
||||
@@ -88,12 +86,11 @@ public class ServletRequestMethodArgumentResolverTests {
|
||||
public void session() throws Exception {
|
||||
MockHttpSession session = new MockHttpSession();
|
||||
servletRequest.setSession(session);
|
||||
|
||||
MethodParameter sessionParameter = new MethodParameter(method, 2);
|
||||
assertTrue("Session not supported", resolver.supportsParameter(sessionParameter));
|
||||
|
||||
boolean isSupported = resolver.supportsParameter(sessionParameter);
|
||||
Object result = resolver.resolveArgument(sessionParameter, mavContainer, webRequest, null);
|
||||
|
||||
assertTrue("Session not supported", isSupported);
|
||||
assertSame("Invalid result", session, result);
|
||||
assertFalse("The requestHandled flag shouldn't change", mavContainer.isRequestHandled());
|
||||
}
|
||||
@@ -107,8 +104,8 @@ public class ServletRequestMethodArgumentResolverTests {
|
||||
}
|
||||
};
|
||||
servletRequest.setUserPrincipal(principal);
|
||||
MethodParameter principalParameter = new MethodParameter(method, 3);
|
||||
|
||||
MethodParameter principalParameter = new MethodParameter(method, 3);
|
||||
assertTrue("Principal not supported", resolver.supportsParameter(principalParameter));
|
||||
|
||||
Object result = resolver.resolveArgument(principalParameter, null, webRequest, null);
|
||||
@@ -119,8 +116,8 @@ public class ServletRequestMethodArgumentResolverTests {
|
||||
public void locale() throws Exception {
|
||||
Locale locale = Locale.ENGLISH;
|
||||
servletRequest.addPreferredLocale(locale);
|
||||
MethodParameter localeParameter = new MethodParameter(method, 4);
|
||||
|
||||
MethodParameter localeParameter = new MethodParameter(method, 4);
|
||||
assertTrue("Locale not supported", resolver.supportsParameter(localeParameter));
|
||||
|
||||
Object result = resolver.resolveArgument(localeParameter, null, webRequest, null);
|
||||
@@ -132,8 +129,8 @@ public class ServletRequestMethodArgumentResolverTests {
|
||||
Locale locale = Locale.ENGLISH;
|
||||
servletRequest.setAttribute(DispatcherServlet.LOCALE_RESOLVER_ATTRIBUTE,
|
||||
new FixedLocaleResolver(locale));
|
||||
MethodParameter localeParameter = new MethodParameter(method, 4);
|
||||
|
||||
MethodParameter localeParameter = new MethodParameter(method, 4);
|
||||
assertTrue("Locale not supported", resolver.supportsParameter(localeParameter));
|
||||
|
||||
Object result = resolver.resolveArgument(localeParameter, null, webRequest, null);
|
||||
@@ -143,7 +140,6 @@ public class ServletRequestMethodArgumentResolverTests {
|
||||
@Test
|
||||
public void timeZone() throws Exception {
|
||||
MethodParameter timeZoneParameter = new MethodParameter(method, 8);
|
||||
|
||||
assertTrue("TimeZone not supported", resolver.supportsParameter(timeZoneParameter));
|
||||
|
||||
Object result = resolver.resolveArgument(timeZoneParameter, null, webRequest, null);
|
||||
@@ -155,8 +151,8 @@ public class ServletRequestMethodArgumentResolverTests {
|
||||
TimeZone timeZone = TimeZone.getTimeZone("America/Los_Angeles");
|
||||
servletRequest.setAttribute(DispatcherServlet.LOCALE_RESOLVER_ATTRIBUTE,
|
||||
new FixedLocaleResolver(Locale.US, timeZone));
|
||||
MethodParameter timeZoneParameter = new MethodParameter(method, 8);
|
||||
|
||||
MethodParameter timeZoneParameter = new MethodParameter(method, 8);
|
||||
assertTrue("TimeZone not supported", resolver.supportsParameter(timeZoneParameter));
|
||||
|
||||
Object result = resolver.resolveArgument(timeZoneParameter, null, webRequest, null);
|
||||
@@ -166,7 +162,6 @@ public class ServletRequestMethodArgumentResolverTests {
|
||||
@Test
|
||||
public void zoneId() throws Exception {
|
||||
MethodParameter zoneIdParameter = new MethodParameter(method, 9);
|
||||
|
||||
assertTrue("ZoneId not supported", resolver.supportsParameter(zoneIdParameter));
|
||||
|
||||
Object result = resolver.resolveArgument(zoneIdParameter, null, webRequest, null);
|
||||
@@ -189,7 +184,6 @@ public class ServletRequestMethodArgumentResolverTests {
|
||||
@Test
|
||||
public void inputStream() throws Exception {
|
||||
MethodParameter inputStreamParameter = new MethodParameter(method, 5);
|
||||
|
||||
assertTrue("InputStream not supported", resolver.supportsParameter(inputStreamParameter));
|
||||
|
||||
Object result = resolver.resolveArgument(inputStreamParameter, null, webRequest, null);
|
||||
@@ -199,7 +193,6 @@ public class ServletRequestMethodArgumentResolverTests {
|
||||
@Test
|
||||
public void reader() throws Exception {
|
||||
MethodParameter readerParameter = new MethodParameter(method, 6);
|
||||
|
||||
assertTrue("Reader not supported", resolver.supportsParameter(readerParameter));
|
||||
|
||||
Object result = resolver.resolveArgument(readerParameter, null, webRequest, null);
|
||||
@@ -209,7 +202,6 @@ public class ServletRequestMethodArgumentResolverTests {
|
||||
@Test
|
||||
public void webRequest() throws Exception {
|
||||
MethodParameter webRequestParameter = new MethodParameter(method, 7);
|
||||
|
||||
assertTrue("WebRequest not supported", resolver.supportsParameter(webRequestParameter));
|
||||
|
||||
Object result = resolver.resolveArgument(webRequestParameter, null, webRequest, null);
|
||||
@@ -219,7 +211,6 @@ public class ServletRequestMethodArgumentResolverTests {
|
||||
@Test
|
||||
public void httpMethod() throws Exception {
|
||||
MethodParameter httpMethodParameter = new MethodParameter(method, 10);
|
||||
|
||||
assertTrue("HttpMethod not supported", resolver.supportsParameter(httpMethodParameter));
|
||||
|
||||
Object result = resolver.resolveArgument(httpMethodParameter, null, webRequest, null);
|
||||
@@ -241,4 +232,4 @@ public class ServletRequestMethodArgumentResolverTests {
|
||||
HttpMethod p10) {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -33,7 +33,7 @@ import org.springframework.web.method.support.ModelAndViewContainer;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Test fixture with {@link org.springframework.web.servlet.mvc.method.annotation.ServletRequestMethodArgumentResolver}.
|
||||
* Test fixture with {@link ServletResponseMethodArgumentResolver}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
@@ -49,6 +49,7 @@ public class ServletResponseMethodArgumentResolverTests {
|
||||
|
||||
private MockHttpServletResponse servletResponse;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
resolver = new ServletResponseMethodArgumentResolver();
|
||||
@@ -58,10 +59,10 @@ public class ServletResponseMethodArgumentResolverTests {
|
||||
webRequest = new ServletWebRequest(new MockHttpServletRequest(), servletResponse);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void servletResponse() throws Exception {
|
||||
MethodParameter servletResponseParameter = new MethodParameter(method, 0);
|
||||
|
||||
assertTrue("ServletResponse not supported", resolver.supportsParameter(servletResponseParameter));
|
||||
|
||||
Object result = resolver.resolveArgument(servletResponseParameter, mavContainer, webRequest, null);
|
||||
@@ -69,8 +70,7 @@ public class ServletResponseMethodArgumentResolverTests {
|
||||
assertTrue(mavContainer.isRequestHandled());
|
||||
}
|
||||
|
||||
// SPR-8983
|
||||
|
||||
@Test // SPR-8983
|
||||
public void servletResponseNoMavContainer() throws Exception {
|
||||
MethodParameter servletResponseParameter = new MethodParameter(method, 0);
|
||||
assertTrue("ServletResponse not supported", resolver.supportsParameter(servletResponseParameter));
|
||||
@@ -82,7 +82,6 @@ public class ServletResponseMethodArgumentResolverTests {
|
||||
@Test
|
||||
public void outputStream() throws Exception {
|
||||
MethodParameter outputStreamParameter = new MethodParameter(method, 1);
|
||||
|
||||
assertTrue("OutputStream not supported", resolver.supportsParameter(outputStreamParameter));
|
||||
|
||||
Object result = resolver.resolveArgument(outputStreamParameter, mavContainer, webRequest, null);
|
||||
@@ -93,7 +92,6 @@ public class ServletResponseMethodArgumentResolverTests {
|
||||
@Test
|
||||
public void writer() throws Exception {
|
||||
MethodParameter writerParameter = new MethodParameter(method, 2);
|
||||
|
||||
assertTrue("Writer not supported", resolver.supportsParameter(writerParameter));
|
||||
|
||||
Object result = resolver.resolveArgument(writerParameter, mavContainer, webRequest, null);
|
||||
@@ -101,7 +99,9 @@ public class ServletResponseMethodArgumentResolverTests {
|
||||
assertTrue(mavContainer.isRequestHandled());
|
||||
}
|
||||
|
||||
public void supportedParams(ServletResponse p0, OutputStream p1, Writer p2) {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void supportedParams(ServletResponse p0, OutputStream p1, Writer p2) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user