Browse Source

Drop Servlet 2.5 runtime compatibility

Issue: SPR-13189
pull/1099/head
Juergen Hoeller 8 years ago
parent
commit
ae0b7c26c5
  1. 7
      spring-web/src/main/java/org/springframework/http/server/ServletServerHttpResponse.java
  2. 67
      spring-web/src/main/java/org/springframework/web/bind/support/WebRequestDataBinder.java
  3. 12
      spring-web/src/main/java/org/springframework/web/context/request/ServletWebRequest.java
  4. 75
      spring-web/src/main/java/org/springframework/web/context/request/async/NoSupportAsyncWebRequest.java
  5. 20
      spring-web/src/main/java/org/springframework/web/context/request/async/WebAsyncUtils.java
  6. 28
      spring-web/src/main/java/org/springframework/web/filter/ShallowEtagHeaderFilter.java
  7. 41
      spring-web/src/main/java/org/springframework/web/multipart/support/MultipartResolutionDelegate.java
  8. 3
      spring-web/src/main/java/org/springframework/web/util/CookieGenerator.java
  9. 11
      spring-webmvc/src/main/java/org/springframework/web/servlet/FrameworkServlet.java
  10. 8
      spring-webmvc/src/main/java/org/springframework/web/servlet/support/WebContentGenerator.java

7
spring-web/src/main/java/org/springframework/http/server/ServletServerHttpResponse.java

@ -39,11 +39,6 @@ import org.springframework.util.CollectionUtils; @@ -39,11 +39,6 @@ import org.springframework.util.CollectionUtils;
*/
public class ServletServerHttpResponse implements ServerHttpResponse {
/** Checking for Servlet 3.0+ HttpServletResponse.getHeader(String) */
private static final boolean servlet3Present =
ClassUtils.hasMethod(HttpServletResponse.class, "getHeader", String.class);
private final HttpServletResponse servletResponse;
private final HttpHeaders headers;
@ -60,7 +55,7 @@ public class ServletServerHttpResponse implements ServerHttpResponse { @@ -60,7 +55,7 @@ public class ServletServerHttpResponse implements ServerHttpResponse {
public ServletServerHttpResponse(HttpServletResponse servletResponse) {
Assert.notNull(servletResponse, "HttpServletResponse must not be null");
this.servletResponse = servletResponse;
this.headers = (servlet3Present ? new ServletResponseHttpHeaders() : new HttpHeaders());
this.headers = new ServletResponseHttpHeaders();
}

67
spring-web/src/main/java/org/springframework/web/bind/support/WebRequestDataBinder.java

@ -22,7 +22,6 @@ import javax.servlet.http.HttpServletRequest; @@ -22,7 +22,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.Part;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.util.ClassUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
@ -116,9 +115,9 @@ public class WebRequestDataBinder extends WebDataBinder { @@ -116,9 +115,9 @@ public class WebRequestDataBinder extends WebDataBinder {
if (multipartRequest != null) {
bindMultipart(multipartRequest.getMultiFileMap(), mpvs);
}
else if (ClassUtils.hasMethod(HttpServletRequest.class, "getParts")) {
HttpServletRequest serlvetRequest = ((NativeWebRequest) request).getNativeRequest(HttpServletRequest.class);
new Servlet3MultipartHelper(isBindEmptyMultipartFiles()).bindParts(serlvetRequest, mpvs);
else {
HttpServletRequest servletRequest = ((NativeWebRequest) request).getNativeRequest(HttpServletRequest.class);
bindParts(servletRequest, mpvs);
}
}
doBind(mpvs);
@ -133,6 +132,29 @@ public class WebRequestDataBinder extends WebDataBinder { @@ -133,6 +132,29 @@ public class WebRequestDataBinder extends WebDataBinder {
return (contentType != null && StringUtils.startsWithIgnoreCase(contentType, "multipart"));
}
private void bindParts(HttpServletRequest request, MutablePropertyValues mpvs) {
try {
MultiValueMap<String, Part> map = new LinkedMultiValueMap<String, Part>();
for (Part part : request.getParts()) {
map.add(part.getName(), part);
}
for (Map.Entry<String, List<Part>> entry: map.entrySet()) {
if (entry.getValue().size() == 1) {
Part part = entry.getValue().get(0);
if (isBindEmptyMultipartFiles() || part.getSize() > 0) {
mpvs.add(entry.getKey(), part);
}
}
else {
mpvs.add(entry.getKey(), entry.getValue());
}
}
}
catch (Exception ex) {
throw new MultipartException("Failed to get request parts", ex);
}
}
/**
* Treats errors as fatal.
* <p>Use this method only if it's an error if the input isn't valid.
@ -145,41 +167,4 @@ public class WebRequestDataBinder extends WebDataBinder { @@ -145,41 +167,4 @@ public class WebRequestDataBinder extends WebDataBinder {
}
}
/**
* Encapsulate Part binding code for Servlet 3.0+ only containers.
* @see javax.servlet.http.Part
*/
private static class Servlet3MultipartHelper {
private final boolean bindEmptyMultipartFiles;
public Servlet3MultipartHelper(boolean bindEmptyMultipartFiles) {
this.bindEmptyMultipartFiles = bindEmptyMultipartFiles;
}
public void bindParts(HttpServletRequest request, MutablePropertyValues mpvs) {
try {
MultiValueMap<String, Part> map = new LinkedMultiValueMap<String, Part>();
for (Part part : request.getParts()) {
map.add(part.getName(), part);
}
for (Map.Entry<String, List<Part>> entry: map.entrySet()) {
if (entry.getValue().size() == 1) {
Part part = entry.getValue().get(0);
if (this.bindEmptyMultipartFiles || part.getSize() > 0) {
mpvs.add(entry.getKey(), part);
}
}
else {
mpvs.add(entry.getKey(), entry.getValue());
}
}
}
catch (Exception ex) {
throw new MultipartException("Failed to get request parts", ex);
}
}
}
}

12
spring-web/src/main/java/org/springframework/web/context/request/ServletWebRequest.java

@ -23,14 +23,12 @@ import java.util.Locale; @@ -23,14 +23,12 @@ import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
@ -73,10 +71,6 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ @@ -73,10 +71,6 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
private static final Pattern ETAG_HEADER_VALUE_PATTERN = Pattern.compile("\\*|\\s*((W\\/)?(\"[^\"]*\"))\\s*,?");
/** Checking for Servlet 3.0+ HttpServletResponse.getHeader(String) */
private static final boolean servlet3Present =
ClassUtils.hasMethod(HttpServletResponse.class, "getHeader", String.class);
private boolean notModified = false;
@ -283,19 +277,19 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ @@ -283,19 +277,19 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
private boolean isCompatibleWithConditionalRequests(HttpServletResponse response) {
try {
if (response == null || !servlet3Present) {
if (response == null) {
// Can't check response.getStatus() - let's assume we're good
return true;
}
return HttpStatus.valueOf(response.getStatus()).is2xxSuccessful();
}
catch (IllegalArgumentException e) {
catch (IllegalArgumentException ex) {
return true;
}
}
private boolean isHeaderAbsent(HttpServletResponse response, String header) {
if (response == null || !servlet3Present) {
if (response == null) {
// Can't check response.getHeader(header) - let's assume it's not set
return true;
}

75
spring-web/src/main/java/org/springframework/web/context/request/async/NoSupportAsyncWebRequest.java

@ -1,75 +0,0 @@ @@ -1,75 +0,0 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.context.request.async;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.context.request.ServletWebRequest;
/**
* An {@code AsyncWebRequest} to use when there is no underlying async support.
*
* @author Rossen Stoyanchev
* @since 3.2
*/
public class NoSupportAsyncWebRequest extends ServletWebRequest implements AsyncWebRequest {
public NoSupportAsyncWebRequest(HttpServletRequest request, HttpServletResponse response) {
super(request, response);
}
@Override
public void addCompletionHandler(Runnable runnable) {
// ignored
}
@Override
public void setTimeout(Long timeout) {
// ignored
}
@Override
public void addTimeoutHandler(Runnable runnable) {
// ignored
}
@Override
public boolean isAsyncStarted() {
return false;
}
// Not supported
@Override
public void startAsync() {
throw new UnsupportedOperationException("No async support in a pre-Servlet 3.0 runtime");
}
@Override
public boolean isAsyncComplete() {
throw new UnsupportedOperationException("No async support in a pre-Servlet 3.0 runtime");
}
@Override
public void dispatch() {
throw new UnsupportedOperationException("No async support in a pre-Servlet 3.0 runtime");
}
}

20
spring-web/src/main/java/org/springframework/web/context/request/async/WebAsyncUtils.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 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,7 +20,6 @@ import javax.servlet.ServletRequest; @@ -20,7 +20,6 @@ import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.util.ClassUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.WebRequest;
@ -35,9 +34,6 @@ public abstract class WebAsyncUtils { @@ -35,9 +34,6 @@ public abstract class WebAsyncUtils {
public static final String WEB_ASYNC_MANAGER_ATTRIBUTE = WebAsyncManager.class.getName() + ".WEB_ASYNC_MANAGER";
// Determine whether Servlet 3.0's ServletRequest.startAsync method is available
private static final boolean startAsyncAvailable = ClassUtils.hasMethod(ServletRequest.class, "startAsync");
/**
* Obtain the {@link WebAsyncManager} for the current request, or if not
@ -76,19 +72,7 @@ public abstract class WebAsyncUtils { @@ -76,19 +72,7 @@ public abstract class WebAsyncUtils {
* @return an AsyncWebRequest instance (never {@code null})
*/
public static AsyncWebRequest createAsyncWebRequest(HttpServletRequest request, HttpServletResponse response) {
return (startAsyncAvailable ? AsyncWebRequestFactory.createStandardAsyncWebRequest(request, response) :
new NoSupportAsyncWebRequest(request, response));
}
/**
* Inner class to avoid a hard dependency on the Servlet 3.0 API.
*/
private static class AsyncWebRequestFactory {
public static AsyncWebRequest createStandardAsyncWebRequest(HttpServletRequest request, HttpServletResponse response) {
return new StandardServletAsyncWebRequest(request, response);
}
return new StandardServletAsyncWebRequest(request, response);
}
}

28
spring-web/src/main/java/org/springframework/web/filter/ShallowEtagHeaderFilter.java

@ -19,7 +19,6 @@ package org.springframework.web.filter; @@ -19,7 +19,6 @@ package org.springframework.web.filter;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
@ -29,7 +28,6 @@ import javax.servlet.http.HttpServletResponse; @@ -29,7 +28,6 @@ import javax.servlet.http.HttpServletResponse;
import org.springframework.http.HttpMethod;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.DigestUtils;
import org.springframework.web.util.ContentCachingResponseWrapper;
import org.springframework.web.util.WebUtils;
@ -61,29 +59,30 @@ public class ShallowEtagHeaderFilter extends OncePerRequestFilter { @@ -61,29 +59,30 @@ public class ShallowEtagHeaderFilter extends OncePerRequestFilter {
private static final String STREAMING_ATTRIBUTE = ShallowEtagHeaderFilter.class.getName() + ".STREAMING";
/** Checking for Servlet 3.0+ HttpServletResponse.getHeader(String) */
private static final boolean servlet3Present =
ClassUtils.hasMethod(HttpServletResponse.class, "getHeader", String.class);
private boolean writeWeakETag = false;
/**
* Set whether the ETag value written to the response should be weak, as per rfc7232.
* Set whether the ETag value written to the response should be weak, as per RFC 7232.
* <p>Should be configured using an {@code <init-param>} for parameter name
* "writeWeakETag" in the filter definition in {@code web.xml}.
* @see <a href="https://tools.ietf.org/html/rfc7232#section-2.3">rfc7232 section-2.3</a>
* @see <a href="https://tools.ietf.org/html/rfc7232#section-2.3">RFC 7232 section 2.3</a>
* @since 4.3
*/
public boolean isWriteWeakETag() {
return writeWeakETag;
public void setWriteWeakETag(boolean writeWeakETag) {
this.writeWeakETag = writeWeakETag;
}
/**
* Return whether the ETag value written to the response should be weak, as per rfc7232.
* Return whether the ETag value written to the response should be weak, as per RFC 7232.
* @since 4.3
*/
public void setWriteWeakETag(boolean writeWeakETag) {
this.writeWeakETag = writeWeakETag;
public boolean isWriteWeakETag() {
return this.writeWeakETag;
}
/**
* The default value is "false" so that the filter may delay the generation of
* an ETag until the last asynchronously dispatched thread.
@ -169,10 +168,7 @@ public class ShallowEtagHeaderFilter extends OncePerRequestFilter { @@ -169,10 +168,7 @@ public class ShallowEtagHeaderFilter extends OncePerRequestFilter {
if (responseStatusCode >= 200 && responseStatusCode < 300 &&
(HttpMethod.GET.matches(method) || HttpMethod.HEAD.matches(method))) {
String cacheControl = null;
if (servlet3Present) {
cacheControl = response.getHeader(HEADER_CACHE_CONTROL);
}
String cacheControl = response.getHeader(HEADER_CACHE_CONTROL);
if (cacheControl == null || !cacheControl.contains(DIRECTIVE_NO_STORE)) {
return true;
}

41
spring-web/src/main/java/org/springframework/web/multipart/support/MultipartResolutionDelegate.java

@ -24,8 +24,6 @@ import javax.servlet.http.Part; @@ -24,8 +24,6 @@ import javax.servlet.http.Part;
import org.springframework.core.GenericCollectionTypeResolver;
import org.springframework.core.MethodParameter;
import org.springframework.util.ClassUtils;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.util.WebUtils;
@ -42,20 +40,6 @@ public abstract class MultipartResolutionDelegate { @@ -42,20 +40,6 @@ public abstract class MultipartResolutionDelegate {
public static final Object UNRESOLVABLE = new Object();
private static Class<?> servletPartClass = null;
static {
try {
servletPartClass = ClassUtils.forName("javax.servlet.http.Part",
MultipartResolutionDelegate.class.getClassLoader());
}
catch (ClassNotFoundException ex) {
// Servlet 3.0 javax.servlet.http.Part type not available -
// Part references simply not supported then.
}
}
public static boolean isMultipartRequest(HttpServletRequest request) {
return (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null ||
isMultipartContent(request));
@ -71,15 +55,7 @@ public abstract class MultipartResolutionDelegate { @@ -71,15 +55,7 @@ public abstract class MultipartResolutionDelegate {
if (unwrapped != null) {
return unwrapped;
}
return adaptToMultipartHttpServletRequest(request);
}
private static MultipartHttpServletRequest adaptToMultipartHttpServletRequest(HttpServletRequest request) {
if (servletPartClass != null) {
// Servlet 3.0 available ..
return new StandardMultipartHttpServletRequest(request);
}
throw new MultipartException("Expected MultipartHttpServletRequest: is a MultipartResolver configured?");
return new StandardMultipartHttpServletRequest(request);
}
@ -87,8 +63,7 @@ public abstract class MultipartResolutionDelegate { @@ -87,8 +63,7 @@ public abstract class MultipartResolutionDelegate {
Class<?> paramType = parameter.getNestedParameterType();
return (MultipartFile.class == paramType ||
isMultipartFileCollection(parameter) || isMultipartFileArray(parameter) ||
(servletPartClass != null && (servletPartClass == paramType ||
isPartCollection(parameter) || isPartArray(parameter))));
(Part.class == paramType || isPartCollection(parameter) || isPartArray(parameter)));
}
public static Object resolveMultipartArgument(String name, MethodParameter parameter, HttpServletRequest request)
@ -100,19 +75,19 @@ public abstract class MultipartResolutionDelegate { @@ -100,19 +75,19 @@ public abstract class MultipartResolutionDelegate {
if (MultipartFile.class == parameter.getNestedParameterType()) {
if (multipartRequest == null && isMultipart) {
multipartRequest = adaptToMultipartHttpServletRequest(request);
multipartRequest = new StandardMultipartHttpServletRequest(request);
}
return (multipartRequest != null ? multipartRequest.getFile(name) : null);
}
else if (isMultipartFileCollection(parameter)) {
if (multipartRequest == null && isMultipart) {
multipartRequest = adaptToMultipartHttpServletRequest(request);
multipartRequest = new StandardMultipartHttpServletRequest(request);
}
return (multipartRequest != null ? multipartRequest.getFiles(name) : null);
}
else if (isMultipartFileArray(parameter)) {
if (multipartRequest == null && isMultipart) {
multipartRequest = adaptToMultipartHttpServletRequest(request);
multipartRequest = new StandardMultipartHttpServletRequest(request);
}
if (multipartRequest != null) {
List<MultipartFile> multipartFiles = multipartRequest.getFiles(name);
@ -122,7 +97,7 @@ public abstract class MultipartResolutionDelegate { @@ -122,7 +97,7 @@ public abstract class MultipartResolutionDelegate {
return null;
}
}
else if (parameter.getNestedParameterType() == servletPartClass) {
else if (Part.class == parameter.getNestedParameterType()) {
return (isMultipart ? RequestPartResolver.resolvePart(request, name) : null);
}
else if (isPartCollection(parameter)) {
@ -145,11 +120,11 @@ public abstract class MultipartResolutionDelegate { @@ -145,11 +120,11 @@ public abstract class MultipartResolutionDelegate {
}
private static boolean isPartCollection(MethodParameter methodParam) {
return (servletPartClass == getCollectionParameterType(methodParam));
return (Part.class == getCollectionParameterType(methodParam));
}
private static boolean isPartArray(MethodParameter methodParam) {
return (servletPartClass == methodParam.getNestedParameterType().getComponentType());
return (Part.class == methodParam.getNestedParameterType().getComponentType());
}
private static Class<?> getCollectionParameterType(MethodParameter methodParam) {

3
spring-web/src/main/java/org/springframework/web/util/CookieGenerator.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 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.
@ -145,7 +145,6 @@ public class CookieGenerator { @@ -145,7 +145,6 @@ public class CookieGenerator {
/**
* Set whether the cookie is supposed to be marked with the "HttpOnly" attribute.
* <p>Note that this feature is only available on Servlet 3.0 and higher.
* @see javax.servlet.http.Cookie#setHttpOnly
*/
public void setCookieHttpOnly(boolean cookieHttpOnly) {

11
spring-webmvc/src/main/java/org/springframework/web/servlet/FrameworkServlet.java

@ -162,11 +162,6 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic @@ -162,11 +162,6 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic
private static final String INIT_PARAM_DELIMITERS = ",; \t\n";
/** Checking for Servlet 3.0+ HttpServletResponse.getStatus() */
private static final boolean responseGetStatusAvailable =
ClassUtils.hasMethod(HttpServletResponse.class, "getStatus");
/** ServletContext attribute to find the WebApplicationContext in */
private String contextAttribute;
@ -912,8 +907,7 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic @@ -912,8 +907,7 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic
}
}
// Use response wrapper for Servlet 2.5 compatibility where
// the getHeader() method does not exist
// Use response wrapper in order to always add PATCH to the allowed methods
super.doOptions(request, new HttpServletResponseWrapper(response) {
@Override
public void setHeader(String name, String value) {
@ -1069,13 +1063,12 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic @@ -1069,13 +1063,12 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic
if (this.publishEvents) {
// Whether or not we succeeded, publish an event.
long processingTime = System.currentTimeMillis() - startTime;
int statusCode = (responseGetStatusAvailable ? response.getStatus() : -1);
this.webApplicationContext.publishEvent(
new ServletRequestHandledEvent(this,
request.getRequestURI(), request.getRemoteAddr(),
request.getMethod(), getServletConfig().getServletName(),
WebUtils.getSessionId(request), getUsernameForRequest(request),
processingTime, failureCause, statusCode));
processingTime, failureCause, response.getStatus()));
}
}

8
spring-webmvc/src/main/java/org/springframework/web/servlet/support/WebContentGenerator.java

@ -80,10 +80,6 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport { @@ -80,10 +80,6 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
protected static final String HEADER_CACHE_CONTROL = "Cache-Control";
/** Checking for Servlet 3.0+ HttpServletResponse.getHeaders(String) */
private static final boolean servlet3Present =
ClassUtils.hasMethod(HttpServletResponse.class, "getHeaders", String.class);
/** Set of supported HTTP methods */
private Set<String> supportedMethods;
@ -263,8 +259,6 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport { @@ -263,8 +259,6 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
* subject to content negotiation and variances based on the value of the
* given request headers. The configured request header names are added only
* if not already present in the response "Vary" header.
* <p><strong>Note:</strong> This property is only supported on Servlet 3.0+
* which allows checking existing response header values.
* @param varyByRequestHeaders one or more request header names
* @since 4.3
*/
@ -398,7 +392,7 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport { @@ -398,7 +392,7 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
else {
applyCacheSeconds(response, this.cacheSeconds);
}
if (servlet3Present && this.varyByRequestHeaders != null) {
if (this.varyByRequestHeaders != null) {
for (String value : getVaryRequestHeadersToAdd(response)) {
response.addHeader("Vary", value);
}

Loading…
Cancel
Save