Polishing

This commit is contained in:
Juergen Hoeller 2014-04-23 23:03:47 +02:00
parent 21f9ca088d
commit ec7d80b851
2 changed files with 29 additions and 38 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2012 the original author or authors. * Copyright 2002-2014 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,7 +17,6 @@
package org.springframework.web.filter; package org.springframework.web.filter;
import java.io.IOException; import java.io.IOException;
import javax.servlet.FilterChain; import javax.servlet.FilterChain;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.ServletRequest; import javax.servlet.ServletRequest;
@ -35,8 +34,8 @@ import org.springframework.web.util.WebUtils;
* method with HttpServletRequest and HttpServletResponse arguments. * method with HttpServletRequest and HttpServletResponse arguments.
* *
* <p>As of Servlet 3.0, a filter may be invoked as part of a * <p>As of Servlet 3.0, a filter may be invoked as part of a
* {@link javax.servlet.DispatcherType.REQUEST REQUEST} or * {@link javax.servlet.DispatcherType#REQUEST REQUEST} or
* {@link javax.servlet.DispatcherType.ASYNC ASYNC} dispatches that occur in * {@link javax.servlet.DispatcherType#ASYNC ASYNC} dispatches that occur in
* separate threads. A filter can be configured in {@code web.xml} whether it * separate threads. A filter can be configured in {@code web.xml} whether it
* should be involved in async dispatches. However, in some cases servlet * should be involved in async dispatches. However, in some cases servlet
* containers assume different default configuration. Therefore sub-classes can * containers assume different default configuration. Therefore sub-classes can
@ -53,7 +52,7 @@ import org.springframework.web.util.WebUtils;
* won't be the last one. * won't be the last one.
* *
* <p>Yet another dispatch type that also occurs in its own thread is * <p>Yet another dispatch type that also occurs in its own thread is
* {@link javax.servlet.DispatcherType.ERROR ERROR}. Sub-classes can override * {@link javax.servlet.DispatcherType#ERROR ERROR}. Sub-classes can override
* {@link #shouldNotFilterErrorDispatch()} if they wish to declare statically * {@link #shouldNotFilterErrorDispatch()} if they wish to declare statically
* if they should be invoked <em>once</em> during error dispatches. * if they should be invoked <em>once</em> during error dispatches.
* *
@ -129,7 +128,6 @@ public abstract class OncePerRequestFilter extends GenericFilterBean {
* in Servlet 3.0 means a filter can be invoked in more than one thread over * in Servlet 3.0 means a filter can be invoked in more than one thread over
* the course of a single request. This method returns {@code true} if the * the course of a single request. This method returns {@code true} if the
* filter is currently executing within an asynchronous dispatch. * filter is currently executing within an asynchronous dispatch.
*
* @param request the current request * @param request the current request
* @see WebAsyncManager#hasConcurrentResult() * @see WebAsyncManager#hasConcurrentResult()
*/ */
@ -140,7 +138,6 @@ public abstract class OncePerRequestFilter extends GenericFilterBean {
/** /**
* Whether request processing is in asynchronous mode meaning that the * Whether request processing is in asynchronous mode meaning that the
* response will not be committed after the current thread is exited. * response will not be committed after the current thread is exited.
*
* @param request the current request * @param request the current request
* @see WebAsyncManager#isConcurrentHandlingStarted() * @see WebAsyncManager#isConcurrentHandlingStarted()
*/ */
@ -151,7 +148,7 @@ public abstract class OncePerRequestFilter extends GenericFilterBean {
/** /**
* Return the name of the request attribute that identifies that a request * Return the name of the request attribute that identifies that a request
* is already filtered. * is already filtered.
* <p>Default implementation takes the configured name of the concrete filter * <p>The default implementation takes the configured name of the concrete filter
* instance and appends ".FILTERED". If the filter is not fully initialized, * instance and appends ".FILTERED". If the filter is not fully initialized,
* it falls back to its class name. * it falls back to its class name.
* @see #getFilterName * @see #getFilterName
@ -188,7 +185,6 @@ public abstract class OncePerRequestFilter extends GenericFilterBean {
* types via {@code web.xml} or in Java through the {@code ServletContext}, * types via {@code web.xml} or in Java through the {@code ServletContext},
* servlet containers may enforce different defaults with regards to * servlet containers may enforce different defaults with regards to
* dispatcher types. This flag enforces the design intent of the filter. * dispatcher types. This flag enforces the design intent of the filter.
*
* <p>The default return value is "true", which means the filter will not be * <p>The default return value is "true", which means the filter will not be
* invoked during subsequent async dispatches. If "false", the filter will * invoked during subsequent async dispatches. If "false", the filter will
* be invoked during async dispatches with the same guarantees of being * be invoked during async dispatches with the same guarantees of being

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2012 the original author or authors. * Copyright 2002-2014 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -22,7 +22,6 @@ import java.util.Collections;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
@ -41,8 +40,8 @@ import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.HandlerMapping; import org.springframework.web.servlet.HandlerMapping;
/** /**
* Extends {@link AbstractMessageConverterMethodArgumentResolver} with the ability to handle method return * Extends {@link AbstractMessageConverterMethodArgumentResolver} with the ability to handle
* values by writing to the response with {@link HttpMessageConverter}s. * method return values by writing to the response with {@link HttpMessageConverter}s.
* *
* @author Arjen Poutsma * @author Arjen Poutsma
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
@ -55,6 +54,7 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
private final ContentNegotiationManager contentNegotiationManager; private final ContentNegotiationManager contentNegotiationManager;
protected AbstractMessageConverterMethodProcessor(List<HttpMessageConverter<?>> messageConverters) { protected AbstractMessageConverterMethodProcessor(List<HttpMessageConverter<?>> messageConverters) {
this(messageConverters, null); this(messageConverters, null);
} }
@ -63,12 +63,12 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
ContentNegotiationManager manager) { ContentNegotiationManager manager) {
super(messageConverters); super(messageConverters);
this.contentNegotiationManager = (manager != null) ? manager : new ContentNegotiationManager(); this.contentNegotiationManager = (manager != null ? manager : new ContentNegotiationManager());
} }
/** /**
* Creates a new {@link HttpOutputMessage} from the given {@link NativeWebRequest}. * Creates a new {@link HttpOutputMessage} from the given {@link NativeWebRequest}.
*
* @param webRequest the web request to create an output message from * @param webRequest the web request to create an output message from
* @return the output message * @return the output message
*/ */
@ -81,10 +81,9 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
* Writes the given return value to the given web request. Delegates to * Writes the given return value to the given web request. Delegates to
* {@link #writeWithMessageConverters(Object, MethodParameter, ServletServerHttpRequest, ServletServerHttpResponse)} * {@link #writeWithMessageConverters(Object, MethodParameter, ServletServerHttpRequest, ServletServerHttpResponse)}
*/ */
protected <T> void writeWithMessageConverters(T returnValue, protected <T> void writeWithMessageConverters(T returnValue, MethodParameter returnType, NativeWebRequest webRequest)
MethodParameter returnType,
NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException { throws IOException, HttpMediaTypeNotAcceptableException {
ServletServerHttpRequest inputMessage = createInputMessage(webRequest); ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest); ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage); writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
@ -92,7 +91,6 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
/** /**
* Writes the given return type to the given output message. * Writes the given return type to the given output message.
*
* @param returnValue the value to write to the output message * @param returnValue the value to write to the output message
* @param returnType the type of the value * @param returnType the type of the value
* @param inputMessage the input messages. Used to inspect the {@code Accept} header. * @param inputMessage the input messages. Used to inspect the {@code Accept} header.
@ -102,23 +100,20 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
* the request cannot be met by the message converters * the request cannot be met by the message converters
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected <T> void writeWithMessageConverters(T returnValue, protected <T> void writeWithMessageConverters(T returnValue, MethodParameter returnType,
MethodParameter returnType, ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
ServletServerHttpRequest inputMessage,
ServletServerHttpResponse outputMessage)
throws IOException, HttpMediaTypeNotAcceptableException { throws IOException, HttpMediaTypeNotAcceptableException {
Class<?> returnValueClass = returnValue.getClass(); Class<?> returnValueClass = returnValue.getClass();
HttpServletRequest servletRequest = inputMessage.getServletRequest(); HttpServletRequest servletRequest = inputMessage.getServletRequest();
List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(servletRequest); List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(servletRequest);
List<MediaType> producibleMediaTypes = getProducibleMediaTypes(servletRequest, returnValueClass); List<MediaType> producibleMediaTypes = getProducibleMediaTypes(servletRequest, returnValueClass);
Set<MediaType> compatibleMediaTypes = new LinkedHashSet<MediaType>(); Set<MediaType> compatibleMediaTypes = new LinkedHashSet<MediaType>();
for (MediaType r : requestedMediaTypes) { for (MediaType requestedType : requestedMediaTypes) {
for (MediaType p : producibleMediaTypes) { for (MediaType producibleType : producibleMediaTypes) {
if (r.isCompatibleWith(p)) { if (requestedType.isCompatibleWith(producibleType)) {
compatibleMediaTypes.add(getMostSpecificMediaType(r, p)); compatibleMediaTypes.add(getMostSpecificMediaType(requestedType, producibleType));
} }
} }
} }
@ -143,7 +138,7 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
if (selectedMediaType != null) { if (selectedMediaType != null) {
selectedMediaType = selectedMediaType.removeQualityValue(); selectedMediaType = selectedMediaType.removeQualityValue();
for (HttpMessageConverter<?> messageConverter : messageConverters) { for (HttpMessageConverter<?> messageConverter : this.messageConverters) {
if (messageConverter.canWrite(returnValueClass, selectedMediaType)) { if (messageConverter.canWrite(returnValueClass, selectedMediaType)) {
((HttpMessageConverter<T>) messageConverter).write(returnValue, selectedMediaType, outputMessage); ((HttpMessageConverter<T>) messageConverter).write(returnValue, selectedMediaType, outputMessage);
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
@ -154,7 +149,7 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
} }
} }
} }
throw new HttpMediaTypeNotAcceptableException(allSupportedMediaTypes); throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes);
} }
/** /**
@ -171,9 +166,9 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
if (!CollectionUtils.isEmpty(mediaTypes)) { if (!CollectionUtils.isEmpty(mediaTypes)) {
return new ArrayList<MediaType>(mediaTypes); return new ArrayList<MediaType>(mediaTypes);
} }
else if (!allSupportedMediaTypes.isEmpty()) { else if (!this.allSupportedMediaTypes.isEmpty()) {
List<MediaType> result = new ArrayList<MediaType>(); List<MediaType> result = new ArrayList<MediaType>();
for (HttpMessageConverter<?> converter : messageConverters) { for (HttpMessageConverter<?> converter : this.messageConverters) {
if (converter.canWrite(returnValueClass, null)) { if (converter.canWrite(returnValueClass, null)) {
result.addAll(converter.getSupportedMediaTypes()); result.addAll(converter.getSupportedMediaTypes());
} }
@ -187,7 +182,7 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
private List<MediaType> getAcceptableMediaTypes(HttpServletRequest request) throws HttpMediaTypeNotAcceptableException { private List<MediaType> getAcceptableMediaTypes(HttpServletRequest request) throws HttpMediaTypeNotAcceptableException {
List<MediaType> mediaTypes = this.contentNegotiationManager.resolveMediaTypes(new ServletWebRequest(request)); List<MediaType> mediaTypes = this.contentNegotiationManager.resolveMediaTypes(new ServletWebRequest(request));
return mediaTypes.isEmpty() ? Collections.singletonList(MediaType.ALL) : mediaTypes; return (mediaTypes.isEmpty() ? Collections.singletonList(MediaType.ALL) : mediaTypes);
} }
/** /**
@ -195,8 +190,8 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
* with the q-value of the former. * with the q-value of the former.
*/ */
private MediaType getMostSpecificMediaType(MediaType acceptType, MediaType produceType) { private MediaType getMostSpecificMediaType(MediaType acceptType, MediaType produceType) {
produceType = produceType.copyQualityValue(acceptType); MediaType produceTypeToUse = produceType.copyQualityValue(acceptType);
return MediaType.SPECIFICITY_COMPARATOR.compare(acceptType, produceType) <= 0 ? acceptType : produceType; return (MediaType.SPECIFICITY_COMPARATOR.compare(acceptType, produceTypeToUse) <= 0 ? acceptType : produceTypeToUse);
} }
} }