Consistent use of @Nullable across the codebase (even for internals)
Beyond just formally declaring the current behavior, this revision actually enforces non-null behavior in selected signatures now, not tolerating null values anymore when not explicitly documented. It also changes some utility methods with historic null-in/null-out tolerance towards enforced non-null return values, making them a proper citizen in non-null assignments. Some issues are left as to-do: in particular a thorough revision of spring-test, and a few tests with unclear failures (ignored as "TODO: NULLABLE") to be sorted out in a follow-up commit. Issue: SPR-15540
This commit is contained in:
@@ -28,7 +28,6 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@@ -1013,9 +1012,12 @@ public class DispatcherServlet extends FrameworkServlet {
|
||||
/**
|
||||
* Do we need view name translation?
|
||||
*/
|
||||
private void applyDefaultViewName(HttpServletRequest request, ModelAndView mv) throws Exception {
|
||||
private void applyDefaultViewName(HttpServletRequest request, @Nullable ModelAndView mv) throws Exception {
|
||||
if (mv != null && !mv.hasView()) {
|
||||
mv.setViewName(getDefaultViewName(request));
|
||||
String defaultViewName = getDefaultViewName(request);
|
||||
if (defaultViewName != null) {
|
||||
mv.setViewName(defaultViewName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1024,7 +1026,8 @@ public class DispatcherServlet extends FrameworkServlet {
|
||||
* either a ModelAndView or an Exception to be resolved to a ModelAndView.
|
||||
*/
|
||||
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
|
||||
HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
|
||||
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
|
||||
@Nullable Exception exception) throws Exception {
|
||||
|
||||
boolean errorView = false;
|
||||
|
||||
@@ -1077,12 +1080,7 @@ public class DispatcherServlet extends FrameworkServlet {
|
||||
return ((LocaleContextResolver) this.localeResolver).resolveLocaleContext(request);
|
||||
}
|
||||
else {
|
||||
return new LocaleContext() {
|
||||
@Override
|
||||
public Locale getLocale() {
|
||||
return localeResolver.resolveLocale(request);
|
||||
}
|
||||
};
|
||||
return () -> localeResolver.resolveLocale(request);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1237,7 +1235,10 @@ public class DispatcherServlet extends FrameworkServlet {
|
||||
}
|
||||
// We might still need view name translation for a plain error model...
|
||||
if (!exMv.hasView()) {
|
||||
exMv.setViewName(getDefaultViewName(request));
|
||||
String defaultViewName = getDefaultViewName(request);
|
||||
if (defaultViewName != null) {
|
||||
exMv.setViewName(defaultViewName);
|
||||
}
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Handler execution resulted in exception - forwarding to resolved error view: " + exMv, ex);
|
||||
@@ -1264,9 +1265,10 @@ public class DispatcherServlet extends FrameworkServlet {
|
||||
response.setLocale(locale);
|
||||
|
||||
View view;
|
||||
if (mv.isReference()) {
|
||||
String viewName = mv.getViewName();
|
||||
if (viewName != null) {
|
||||
// We need to resolve the view name.
|
||||
view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
|
||||
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
|
||||
if (view == null) {
|
||||
throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
|
||||
"' in servlet with name '" + getServletName() + "'");
|
||||
@@ -1326,8 +1328,8 @@ public class DispatcherServlet extends FrameworkServlet {
|
||||
* @see ViewResolver#resolveViewName
|
||||
*/
|
||||
@Nullable
|
||||
protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale,
|
||||
HttpServletRequest request) throws Exception {
|
||||
protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
|
||||
Locale locale, HttpServletRequest request) throws Exception {
|
||||
|
||||
for (ViewResolver viewResolver : this.viewResolvers) {
|
||||
View view = viewResolver.resolveViewName(viewName, locale);
|
||||
@@ -1339,7 +1341,7 @@ public class DispatcherServlet extends FrameworkServlet {
|
||||
}
|
||||
|
||||
private void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response,
|
||||
HandlerExecutionChain mappedHandler, Exception ex) throws Exception {
|
||||
@Nullable HandlerExecutionChain mappedHandler, Exception ex) throws Exception {
|
||||
|
||||
if (mappedHandler != null) {
|
||||
mappedHandler.triggerAfterCompletion(request, response, ex);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -61,7 +61,7 @@ public final class FlashMap extends HashMap<String, Object> implements Comparabl
|
||||
* <p>The path may be absolute (e.g. "/application/resource") or relative to the
|
||||
* current request (e.g. "../resource").
|
||||
*/
|
||||
public void setTargetRequestPath(String path) {
|
||||
public void setTargetRequestPath(@Nullable String path) {
|
||||
this.targetRequestPath = path;
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ public final class FlashMap extends HashMap<String, Object> implements Comparabl
|
||||
* Provide request parameters identifying the request for this FlashMap.
|
||||
* @param params a Map with the names and values of expected parameters
|
||||
*/
|
||||
public FlashMap addTargetRequestParams(MultiValueMap<String, String> params) {
|
||||
public FlashMap addTargetRequestParams(@Nullable MultiValueMap<String, String> params) {
|
||||
if (params != null) {
|
||||
for (String key : params.keySet()) {
|
||||
for (String value : params.get(key)) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -21,7 +21,6 @@ import java.security.Principal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@@ -288,6 +287,7 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic
|
||||
* Return the name of the ServletContext attribute which should be used to retrieve the
|
||||
* {@link WebApplicationContext} that this servlet is supposed to use.
|
||||
*/
|
||||
@Nullable
|
||||
public String getContextAttribute() {
|
||||
return this.contextAttribute;
|
||||
}
|
||||
@@ -368,7 +368,7 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic
|
||||
* @see #applyInitializers
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void setContextInitializers(ApplicationContextInitializer<?>... initializers) {
|
||||
public void setContextInitializers(@Nullable ApplicationContextInitializer<?>... initializers) {
|
||||
if (initializers != null) {
|
||||
for (ApplicationContextInitializer<?> initializer : initializers) {
|
||||
this.contextInitializers.add((ApplicationContextInitializer<ConfigurableApplicationContext>) initializer);
|
||||
@@ -629,8 +629,10 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic
|
||||
|
||||
wac.setEnvironment(getEnvironment());
|
||||
wac.setParent(parent);
|
||||
wac.setConfigLocation(getContextConfigLocation());
|
||||
|
||||
String configLocation = getContextConfigLocation();
|
||||
if (configLocation != null) {
|
||||
wac.setConfigLocation(configLocation);
|
||||
}
|
||||
configureAndRefreshWebApplicationContext(wac);
|
||||
|
||||
return wac;
|
||||
@@ -968,11 +970,7 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic
|
||||
try {
|
||||
doService(request, response);
|
||||
}
|
||||
catch (ServletException ex) {
|
||||
failureCause = ex;
|
||||
throw ex;
|
||||
}
|
||||
catch (IOException ex) {
|
||||
catch (ServletException | IOException ex) {
|
||||
failureCause = ex;
|
||||
throw ex;
|
||||
}
|
||||
@@ -1029,8 +1027,8 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic
|
||||
* @see RequestContextHolder#setRequestAttributes
|
||||
*/
|
||||
@Nullable
|
||||
protected ServletRequestAttributes buildRequestAttributes(
|
||||
HttpServletRequest request, HttpServletResponse response, @Nullable RequestAttributes previousAttributes) {
|
||||
protected ServletRequestAttributes buildRequestAttributes(HttpServletRequest request,
|
||||
@Nullable HttpServletResponse response, @Nullable RequestAttributes previousAttributes) {
|
||||
|
||||
if (previousAttributes == null || previousAttributes instanceof ServletRequestAttributes) {
|
||||
return new ServletRequestAttributes(request, response);
|
||||
@@ -1040,8 +1038,8 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic
|
||||
}
|
||||
}
|
||||
|
||||
private void initContextHolders(
|
||||
HttpServletRequest request, LocaleContext localeContext, RequestAttributes requestAttributes) {
|
||||
private void initContextHolders(HttpServletRequest request,
|
||||
@Nullable LocaleContext localeContext, @Nullable RequestAttributes requestAttributes) {
|
||||
|
||||
if (localeContext != null) {
|
||||
LocaleContextHolder.setLocaleContext(localeContext, this.threadContextInheritable);
|
||||
@@ -1064,8 +1062,8 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic
|
||||
}
|
||||
}
|
||||
|
||||
private void publishRequestHandledEvent(
|
||||
HttpServletRequest request, HttpServletResponse response, long startTime, Throwable failureCause) {
|
||||
private void publishRequestHandledEvent(HttpServletRequest request, HttpServletResponse response,
|
||||
long startTime, @Nullable Throwable failureCause) {
|
||||
|
||||
if (this.publishEvents) {
|
||||
// Whether or not we succeeded, publish an event.
|
||||
@@ -1135,7 +1133,8 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic
|
||||
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
|
||||
if (request != null) {
|
||||
HttpServletResponse response = webRequest.getNativeRequest(HttpServletResponse.class);
|
||||
initContextHolders(request, buildLocaleContext(request), buildRequestAttributes(request, response, null));
|
||||
initContextHolders(request, buildLocaleContext(request),
|
||||
buildRequestAttributes(request, response, null));
|
||||
}
|
||||
}
|
||||
@Override
|
||||
|
||||
@@ -18,7 +18,6 @@ package org.springframework.web.servlet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
@@ -64,7 +63,7 @@ public class HandlerExecutionChain {
|
||||
* @param interceptors the array of interceptors to apply
|
||||
* (in the given order) before the handler itself executes
|
||||
*/
|
||||
public HandlerExecutionChain(@Nullable Object handler, HandlerInterceptor... interceptors) {
|
||||
public HandlerExecutionChain(@Nullable Object handler, @Nullable HandlerInterceptor... interceptors) {
|
||||
if (handler instanceof HandlerExecutionChain) {
|
||||
HandlerExecutionChain originalChain = (HandlerExecutionChain) handler;
|
||||
this.handler = originalChain.getHandler();
|
||||
@@ -147,7 +146,9 @@ public class HandlerExecutionChain {
|
||||
/**
|
||||
* Apply postHandle methods of registered interceptors.
|
||||
*/
|
||||
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
|
||||
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
|
||||
throws Exception {
|
||||
|
||||
HandlerInterceptor[] interceptors = getInterceptors();
|
||||
if (!ObjectUtils.isEmpty(interceptors)) {
|
||||
for (int i = interceptors.length - 1; i >= 0; i--) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -146,7 +146,7 @@ public interface HandlerInterceptor {
|
||||
* @throws Exception in case of errors
|
||||
*/
|
||||
default void afterCompletion(
|
||||
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
|
||||
HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex)
|
||||
throws Exception {
|
||||
}
|
||||
|
||||
|
||||
@@ -19,9 +19,7 @@ package org.springframework.web.servlet;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
|
||||
@@ -205,21 +203,10 @@ public abstract class HttpServletBean extends HttpServlet implements Environment
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public final String getServletName() {
|
||||
public String getServletName() {
|
||||
return (getServletConfig() != null ? getServletConfig().getServletName() : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden method that simply returns {@code null} when no
|
||||
* ServletConfig set yet.
|
||||
* @see #getServletConfig()
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public final ServletContext getServletContext() {
|
||||
return (getServletConfig() != null ? getServletConfig().getServletContext() : null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* PropertyValues implementation created from ServletConfig init parameters.
|
||||
|
||||
@@ -145,7 +145,7 @@ public class ModelAndView {
|
||||
* (to be set just prior to View rendering)
|
||||
* @since 4.3
|
||||
*/
|
||||
public ModelAndView(String viewName, @Nullable Map<String, ?> model, HttpStatus status) {
|
||||
public ModelAndView(@Nullable String viewName, @Nullable Map<String, ?> model, @Nullable HttpStatus status) {
|
||||
this.view = viewName;
|
||||
if (model != null) {
|
||||
getModelMap().addAllAttributes(model);
|
||||
@@ -182,7 +182,7 @@ public class ModelAndView {
|
||||
* DispatcherServlet via a ViewResolver. Will override any
|
||||
* pre-existing view name or View.
|
||||
*/
|
||||
public void setViewName(String viewName) {
|
||||
public void setViewName(@Nullable String viewName) {
|
||||
this.view = viewName;
|
||||
}
|
||||
|
||||
@@ -199,7 +199,7 @@ public class ModelAndView {
|
||||
* Set a View object for this ModelAndView. Will override any
|
||||
* pre-existing view name or View.
|
||||
*/
|
||||
public void setView(View view) {
|
||||
public void setView(@Nullable View view) {
|
||||
this.view = view;
|
||||
}
|
||||
|
||||
@@ -304,7 +304,7 @@ public class ModelAndView {
|
||||
* @see ModelMap#addAllAttributes(Map)
|
||||
* @see #getModelMap()
|
||||
*/
|
||||
public ModelAndView addAllObjects(Map<String, ?> modelMap) {
|
||||
public ModelAndView addAllObjects(@Nullable Map<String, ?> modelMap) {
|
||||
getModelMap().addAllAttributes(modelMap);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -17,7 +17,6 @@
|
||||
package org.springframework.web.servlet;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@@ -202,16 +201,7 @@ public class ResourceServlet extends HttpServletBean {
|
||||
try {
|
||||
doInclude(request, response, resourceUrl);
|
||||
}
|
||||
catch (ServletException ex) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Failed to include content of resource [" + resourceUrl + "]", ex);
|
||||
}
|
||||
// Try including default URL if appropriate.
|
||||
if (!includeDefaultUrl(request, response)) {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
catch (ServletException | IOException ex) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Failed to include content of resource [" + resourceUrl + "]", ex);
|
||||
}
|
||||
@@ -275,16 +265,16 @@ public class ResourceServlet extends HttpServletBean {
|
||||
}
|
||||
String[] resourceUrls =
|
||||
StringUtils.tokenizeToStringArray(resourceUrl, RESOURCE_URL_DELIMITERS);
|
||||
for (int i = 0; i < resourceUrls.length; i++) {
|
||||
for (String url : resourceUrls) {
|
||||
// check whether URL matches allowed resources
|
||||
if (this.allowedResources != null && !this.pathMatcher.match(this.allowedResources, resourceUrls[i])) {
|
||||
throw new ServletException("Resource [" + resourceUrls[i] +
|
||||
if (this.allowedResources != null && !this.pathMatcher.match(this.allowedResources, url)) {
|
||||
throw new ServletException("Resource [" + url +
|
||||
"] does not match allowed pattern [" + this.allowedResources + "]");
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Including resource [" + resourceUrls[i] + "]");
|
||||
logger.debug("Including resource [" + url + "]");
|
||||
}
|
||||
RequestDispatcher rd = request.getRequestDispatcher(resourceUrls[i]);
|
||||
RequestDispatcher rd = request.getRequestDispatcher(url);
|
||||
rd.include(request, response);
|
||||
}
|
||||
}
|
||||
@@ -312,8 +302,8 @@ public class ResourceServlet extends HttpServletBean {
|
||||
if (resourceUrl != null) {
|
||||
String[] resourceUrls = StringUtils.tokenizeToStringArray(resourceUrl, RESOURCE_URL_DELIMITERS);
|
||||
long latestTimestamp = -1;
|
||||
for (int i = 0; i < resourceUrls.length; i++) {
|
||||
long timestamp = getFileTimestamp(resourceUrls[i]);
|
||||
for (String url : resourceUrls) {
|
||||
long timestamp = getFileTimestamp(url);
|
||||
if (timestamp > latestTimestamp) {
|
||||
latestTimestamp = timestamp;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ package org.springframework.web.servlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Interface for web-based theme resolution strategies that allows for
|
||||
* both theme resolution via the request and theme modification via
|
||||
@@ -58,10 +60,10 @@ public interface ThemeResolver {
|
||||
* Set the current theme name to the given one.
|
||||
* @param request request to be used for theme name modification
|
||||
* @param response response to be used for theme name modification
|
||||
* @param themeName the new theme name
|
||||
* @param themeName the new theme name ({@code null} or empty to reset it)
|
||||
* @throws UnsupportedOperationException if the ThemeResolver implementation
|
||||
* does not support dynamic changing of the theme
|
||||
*/
|
||||
void setThemeName(HttpServletRequest request, HttpServletResponse response, String themeName);
|
||||
void setThemeName(HttpServletRequest request, HttpServletResponse response, @Nullable String themeName);
|
||||
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConvert
|
||||
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
|
||||
import org.springframework.http.converter.xml.SourceHttpMessageConverter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
@@ -340,7 +341,9 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
}
|
||||
|
||||
private RuntimeBeanReference getConversionService(Element element, Object source, ParserContext parserContext) {
|
||||
private RuntimeBeanReference getConversionService(
|
||||
Element element, @Nullable Object source, ParserContext parserContext) {
|
||||
|
||||
RuntimeBeanReference conversionServiceRef;
|
||||
if (element.hasAttribute("conversion-service")) {
|
||||
conversionServiceRef = new RuntimeBeanReference(element.getAttribute("conversion-service"));
|
||||
@@ -357,7 +360,7 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private RuntimeBeanReference getValidator(Element element, Object source, ParserContext parserContext) {
|
||||
private RuntimeBeanReference getValidator(Element element, @Nullable Object source, ParserContext parserContext) {
|
||||
if (element.hasAttribute("validator")) {
|
||||
return new RuntimeBeanReference(element.getAttribute("validator"));
|
||||
}
|
||||
@@ -375,7 +378,7 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
}
|
||||
|
||||
private RuntimeBeanReference getContentNegotiationManager(Element element, Object source,
|
||||
private RuntimeBeanReference getContentNegotiationManager(Element element, @Nullable Object source,
|
||||
ParserContext parserContext) {
|
||||
|
||||
RuntimeBeanReference beanRef;
|
||||
@@ -478,7 +481,9 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
|
||||
return null;
|
||||
}
|
||||
|
||||
private ManagedList<?> getCallableInterceptors(Element element, Object source, ParserContext parserContext) {
|
||||
private ManagedList<?> getCallableInterceptors(
|
||||
Element element, @Nullable Object source, ParserContext parserContext) {
|
||||
|
||||
ManagedList<? super Object> interceptors = new ManagedList<>();
|
||||
Element asyncElement = DomUtils.getChildElementByTagName(element, "async-support");
|
||||
if (asyncElement != null) {
|
||||
@@ -487,15 +492,19 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
|
||||
interceptors.setSource(source);
|
||||
for (Element converter : DomUtils.getChildElementsByTagName(interceptorsElement, "bean")) {
|
||||
BeanDefinitionHolder beanDef = parserContext.getDelegate().parseBeanDefinitionElement(converter);
|
||||
beanDef = parserContext.getDelegate().decorateBeanDefinitionIfRequired(converter, beanDef);
|
||||
interceptors.add(beanDef);
|
||||
if (beanDef != null) {
|
||||
beanDef = parserContext.getDelegate().decorateBeanDefinitionIfRequired(converter, beanDef);
|
||||
interceptors.add(beanDef);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return interceptors;
|
||||
}
|
||||
|
||||
private ManagedList<?> getDeferredResultInterceptors(Element element, Object source, ParserContext parserContext) {
|
||||
private ManagedList<?> getDeferredResultInterceptors(
|
||||
Element element, @Nullable Object source, ParserContext parserContext) {
|
||||
|
||||
ManagedList<? super Object> interceptors = new ManagedList<>();
|
||||
Element asyncElement = DomUtils.getChildElementByTagName(element, "async-support");
|
||||
if (asyncElement != null) {
|
||||
@@ -504,8 +513,10 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
|
||||
interceptors.setSource(source);
|
||||
for (Element converter : DomUtils.getChildElementsByTagName(interceptorsElement, "bean")) {
|
||||
BeanDefinitionHolder beanDef = parserContext.getDelegate().parseBeanDefinitionElement(converter);
|
||||
beanDef = parserContext.getDelegate().decorateBeanDefinitionIfRequired(converter, beanDef);
|
||||
interceptors.add(beanDef);
|
||||
if (beanDef != null) {
|
||||
beanDef = parserContext.getDelegate().decorateBeanDefinitionIfRequired(converter, beanDef);
|
||||
interceptors.add(beanDef);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -528,6 +539,7 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
|
||||
if (object instanceof BeanDefinitionHolder) {
|
||||
BeanDefinitionHolder beanDef = (BeanDefinitionHolder) object;
|
||||
String className = beanDef.getBeanDefinition().getBeanClassName();
|
||||
Assert.notNull(className, "No resolver class");
|
||||
Class<?> clazz = ClassUtils.resolveClassName(className, context.getReaderContext().getBeanClassLoader());
|
||||
if (WebArgumentResolver.class.isAssignableFrom(clazz)) {
|
||||
RootBeanDefinition adapter = new RootBeanDefinition(ServletWebArgumentResolverAdapter.class);
|
||||
@@ -546,7 +558,7 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
|
||||
return (handlers != null ? extractBeanSubElements(handlers, parserContext) : null);
|
||||
}
|
||||
|
||||
private ManagedList<?> getMessageConverters(Element element, Object source, ParserContext parserContext) {
|
||||
private ManagedList<?> getMessageConverters(Element element, @Nullable Object source, ParserContext parserContext) {
|
||||
Element convertersElement = DomUtils.getChildElementByTagName(element, "message-converters");
|
||||
ManagedList<? super Object> messageConverters = new ManagedList<>();
|
||||
if (convertersElement != null) {
|
||||
@@ -613,7 +625,7 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
|
||||
return messageConverters;
|
||||
}
|
||||
|
||||
private GenericBeanDefinition createObjectMapperFactoryDefinition(Object source) {
|
||||
private GenericBeanDefinition createObjectMapperFactoryDefinition(@Nullable Object source) {
|
||||
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
|
||||
beanDefinition.setBeanClass(Jackson2ObjectMapperFactoryBean.class);
|
||||
beanDefinition.setSource(source);
|
||||
@@ -621,7 +633,7 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
|
||||
return beanDefinition;
|
||||
}
|
||||
|
||||
private RootBeanDefinition createConverterDefinition(Class<?> converterClass, Object source) {
|
||||
private RootBeanDefinition createConverterDefinition(Class<?> converterClass, @Nullable Object source) {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(converterClass);
|
||||
beanDefinition.setSource(source);
|
||||
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -80,7 +80,8 @@ public class CorsBeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
}
|
||||
|
||||
MvcNamespaceUtils.registerCorsConfigurations(corsConfigurations, parserContext, parserContext.extractSource(element));
|
||||
MvcNamespaceUtils.registerCorsConfigurations(
|
||||
corsConfigurations, parserContext, parserContext.extractSource(element));
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -58,7 +58,7 @@ abstract class MvcNamespaceUtils {
|
||||
private static final String CORS_CONFIGURATION_BEAN_NAME = "mvcCorsConfigurations";
|
||||
|
||||
|
||||
public static void registerDefaultComponents(ParserContext parserContext, Object source) {
|
||||
public static void registerDefaultComponents(ParserContext parserContext, @Nullable Object source) {
|
||||
registerBeanNameUrlHandlerMapping(parserContext, source);
|
||||
registerHttpRequestHandlerAdapter(parserContext, source);
|
||||
registerSimpleControllerHandlerAdapter(parserContext, source);
|
||||
@@ -69,7 +69,9 @@ abstract class MvcNamespaceUtils {
|
||||
* under that well-known name, unless already registered.
|
||||
* @return a RuntimeBeanReference to this {@link UrlPathHelper} instance
|
||||
*/
|
||||
public static RuntimeBeanReference registerUrlPathHelper(@Nullable RuntimeBeanReference urlPathHelperRef, ParserContext parserContext, Object source) {
|
||||
public static RuntimeBeanReference registerUrlPathHelper(
|
||||
@Nullable RuntimeBeanReference urlPathHelperRef, ParserContext parserContext, @Nullable Object source) {
|
||||
|
||||
if (urlPathHelperRef != null) {
|
||||
if (parserContext.getRegistry().isAlias(URL_PATH_HELPER_BEAN_NAME)) {
|
||||
parserContext.getRegistry().removeAlias(URL_PATH_HELPER_BEAN_NAME);
|
||||
@@ -92,7 +94,9 @@ abstract class MvcNamespaceUtils {
|
||||
* under that well-known name, unless already registered.
|
||||
* @return a RuntimeBeanReference to this {@link PathMatcher} instance
|
||||
*/
|
||||
public static RuntimeBeanReference registerPathMatcher(@Nullable RuntimeBeanReference pathMatcherRef, ParserContext parserContext, Object source) {
|
||||
public static RuntimeBeanReference registerPathMatcher(@Nullable RuntimeBeanReference pathMatcherRef,
|
||||
ParserContext parserContext, @Nullable Object source) {
|
||||
|
||||
if (pathMatcherRef != null) {
|
||||
if (parserContext.getRegistry().isAlias(PATH_MATCHER_BEAN_NAME)) {
|
||||
parserContext.getRegistry().removeAlias(PATH_MATCHER_BEAN_NAME);
|
||||
@@ -114,7 +118,7 @@ abstract class MvcNamespaceUtils {
|
||||
* Registers an {@link HttpRequestHandlerAdapter} under a well-known
|
||||
* name unless already registered.
|
||||
*/
|
||||
private static void registerBeanNameUrlHandlerMapping(ParserContext parserContext, Object source) {
|
||||
private static void registerBeanNameUrlHandlerMapping(ParserContext parserContext, @Nullable Object source) {
|
||||
if (!parserContext.getRegistry().containsBeanDefinition(BEAN_NAME_URL_HANDLER_MAPPING_BEAN_NAME)){
|
||||
RootBeanDefinition beanNameMappingDef = new RootBeanDefinition(BeanNameUrlHandlerMapping.class);
|
||||
beanNameMappingDef.setSource(source);
|
||||
@@ -131,7 +135,7 @@ abstract class MvcNamespaceUtils {
|
||||
* Registers an {@link HttpRequestHandlerAdapter} under a well-known
|
||||
* name unless already registered.
|
||||
*/
|
||||
private static void registerHttpRequestHandlerAdapter(ParserContext parserContext, Object source) {
|
||||
private static void registerHttpRequestHandlerAdapter(ParserContext parserContext, @Nullable Object source) {
|
||||
if (!parserContext.getRegistry().containsBeanDefinition(HTTP_REQUEST_HANDLER_ADAPTER_BEAN_NAME)) {
|
||||
RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(HttpRequestHandlerAdapter.class);
|
||||
handlerAdapterDef.setSource(source);
|
||||
@@ -145,7 +149,7 @@ abstract class MvcNamespaceUtils {
|
||||
* Registers a {@link SimpleControllerHandlerAdapter} under a well-known
|
||||
* name unless already registered.
|
||||
*/
|
||||
private static void registerSimpleControllerHandlerAdapter(ParserContext parserContext, Object source) {
|
||||
private static void registerSimpleControllerHandlerAdapter(ParserContext parserContext, @Nullable Object source) {
|
||||
if (!parserContext.getRegistry().containsBeanDefinition(SIMPLE_CONTROLLER_HANDLER_ADAPTER_BEAN_NAME)) {
|
||||
RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(SimpleControllerHandlerAdapter.class);
|
||||
handlerAdapterDef.setSource(source);
|
||||
@@ -161,7 +165,10 @@ abstract class MvcNamespaceUtils {
|
||||
* if a non-null CORS configuration is provided.
|
||||
* @return a RuntimeBeanReference to this {@code Map<String, CorsConfiguration>} instance
|
||||
*/
|
||||
public static RuntimeBeanReference registerCorsConfigurations(@Nullable Map<String, CorsConfiguration> corsConfigurations, ParserContext parserContext, Object source) {
|
||||
public static RuntimeBeanReference registerCorsConfigurations(
|
||||
@Nullable Map<String, CorsConfiguration> corsConfigurations,
|
||||
ParserContext parserContext, @Nullable Object source) {
|
||||
|
||||
if (!parserContext.getRegistry().containsBeanDefinition(CORS_CONFIGURATION_BEAN_NAME)) {
|
||||
RootBeanDefinition corsConfigurationsDef = new RootBeanDefinition(LinkedHashMap.class);
|
||||
corsConfigurationsDef.setSource(source);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -34,10 +34,11 @@ import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.cache.concurrent.ConcurrentMapCache;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.http.CacheControl;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.springframework.http.CacheControl;
|
||||
import org.springframework.web.servlet.handler.MappedInterceptor;
|
||||
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
|
||||
import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter;
|
||||
@@ -131,7 +132,7 @@ class ResourcesBeanDefinitionParser implements BeanDefinitionParser {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void registerUrlProvider(ParserContext parserContext, Object source) {
|
||||
private void registerUrlProvider(ParserContext parserContext, @Nullable Object source) {
|
||||
if (!parserContext.getRegistry().containsBeanDefinition(RESOURCE_URL_PROVIDER)) {
|
||||
RootBeanDefinition urlProvider = new RootBeanDefinition(ResourceUrlProvider.class);
|
||||
urlProvider.setSource(source);
|
||||
@@ -153,7 +154,7 @@ class ResourcesBeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
}
|
||||
|
||||
private String registerResourceHandler(ParserContext parserContext, Element element, Object source) {
|
||||
private String registerResourceHandler(ParserContext parserContext, Element element, @Nullable Object source) {
|
||||
String locationAttr = element.getAttribute("location");
|
||||
if (!StringUtils.hasText(locationAttr)) {
|
||||
parserContext.getReaderContext().error("The 'location' attribute is required.", parserContext.extractSource(element));
|
||||
@@ -199,7 +200,7 @@ class ResourcesBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
|
||||
private void parseResourceChain(RootBeanDefinition resourceHandlerDef, ParserContext parserContext,
|
||||
Element element, Object source) {
|
||||
Element element, @Nullable Object source) {
|
||||
|
||||
String autoRegistration = element.getAttribute("auto-registration");
|
||||
boolean isAutoRegistration = !(StringUtils.hasText(autoRegistration) && "false".equals(autoRegistration));
|
||||
@@ -262,7 +263,7 @@ class ResourcesBeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
|
||||
private void parseResourceCache(ManagedList<? super Object> resourceResolvers,
|
||||
ManagedList<? super Object> resourceTransformers, Element element, Object source) {
|
||||
ManagedList<? super Object> resourceTransformers, Element element, @Nullable Object source) {
|
||||
|
||||
String resourceCache = element.getAttribute("resource-cache");
|
||||
if ("true".equals(resourceCache)) {
|
||||
@@ -302,7 +303,7 @@ class ResourcesBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
private void parseResourceResolversTransformers(boolean isAutoRegistration,
|
||||
ManagedList<? super Object> resourceResolvers, ManagedList<? super Object> resourceTransformers,
|
||||
ParserContext parserContext, Element element, Object source) {
|
||||
ParserContext parserContext, Element element, @Nullable Object source) {
|
||||
|
||||
Element resolversElement = DomUtils.getChildElementByTagName(element, "resolvers");
|
||||
if (resolversElement != null) {
|
||||
@@ -347,7 +348,9 @@ class ResourcesBeanDefinitionParser implements BeanDefinitionParser {
|
||||
}
|
||||
}
|
||||
|
||||
private RootBeanDefinition parseVersionResolver(ParserContext parserContext, Element element, Object source) {
|
||||
private RootBeanDefinition parseVersionResolver(
|
||||
ParserContext parserContext, Element element, @Nullable Object source) {
|
||||
|
||||
ManagedMap<String, ? super Object> strategyMap = new ManagedMap<>();
|
||||
strategyMap.setSource(source);
|
||||
RootBeanDefinition versionResolverDef = new RootBeanDefinition(VersionResourceResolver.class);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -28,6 +28,7 @@ import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
|
||||
import org.springframework.web.servlet.mvc.ParameterizableViewController;
|
||||
import org.springframework.web.servlet.view.RedirectView;
|
||||
@@ -100,11 +101,8 @@ class ViewControllerBeanDefinitionParser implements BeanDefinitionParser {
|
||||
throw new IllegalStateException("Unexpected tag name: " + name);
|
||||
}
|
||||
|
||||
Map<String, BeanDefinition> urlMap;
|
||||
if (hm.getPropertyValues().contains("urlMap")) {
|
||||
urlMap = (Map<String, BeanDefinition>) hm.getPropertyValues().getPropertyValue("urlMap").getValue();
|
||||
}
|
||||
else {
|
||||
Map<String, BeanDefinition> urlMap = (Map<String, BeanDefinition>) hm.getPropertyValues().get("urlMap");
|
||||
if (urlMap == null) {
|
||||
urlMap = new ManagedMap<>();
|
||||
hm.getPropertyValues().add("urlMap", urlMap);
|
||||
}
|
||||
@@ -113,7 +111,7 @@ class ViewControllerBeanDefinitionParser implements BeanDefinitionParser {
|
||||
return null;
|
||||
}
|
||||
|
||||
private BeanDefinition registerHandlerMapping(ParserContext context, Object source) {
|
||||
private BeanDefinition registerHandlerMapping(ParserContext context, @Nullable Object source) {
|
||||
if (context.getRegistry().containsBeanDefinition(HANDLER_MAPPING_BEAN_NAME)) {
|
||||
return context.getRegistry().getBeanDefinition(HANDLER_MAPPING_BEAN_NAME);
|
||||
}
|
||||
@@ -132,7 +130,7 @@ class ViewControllerBeanDefinitionParser implements BeanDefinitionParser {
|
||||
return beanDef;
|
||||
}
|
||||
|
||||
private RootBeanDefinition getRedirectView(Element element, HttpStatus status, Object source) {
|
||||
private RootBeanDefinition getRedirectView(Element element, @Nullable HttpStatus status, @Nullable Object source) {
|
||||
RootBeanDefinition redirectView = new RootBeanDefinition(RedirectView.class);
|
||||
redirectView.setSource(source);
|
||||
redirectView.getConstructorArgumentValues().addIndexedArgumentValue(0, element.getAttribute("redirect-url"));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.servlet.config.annotation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -22,7 +23,7 @@ import java.util.concurrent.Callable;
|
||||
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.web.context.request.async.CallableProcessingInterceptor;
|
||||
import org.springframework.web.context.request.async.DeferredResult;
|
||||
import org.springframework.web.context.request.async.DeferredResultProcessingInterceptor;
|
||||
@@ -40,27 +41,22 @@ public class AsyncSupportConfigurer {
|
||||
|
||||
private Long timeout;
|
||||
|
||||
private final List<CallableProcessingInterceptor> callableInterceptors =
|
||||
new ArrayList<>();
|
||||
private final List<CallableProcessingInterceptor> callableInterceptors = new ArrayList<>();
|
||||
|
||||
private final List<DeferredResultProcessingInterceptor> deferredResultInterceptors =
|
||||
new ArrayList<>();
|
||||
private final List<DeferredResultProcessingInterceptor> deferredResultInterceptors = new ArrayList<>();
|
||||
|
||||
|
||||
/**
|
||||
* Set the default {@link AsyncTaskExecutor} to use when a controller method
|
||||
* returns a {@link Callable}. Controller methods can override this default on
|
||||
* a per-request basis by returning a {@link WebAsyncTask}.
|
||||
*
|
||||
* <p>By default a {@link SimpleAsyncTaskExecutor} instance is used, and it's
|
||||
* highly recommended to change that default in production since the simple
|
||||
* executor does not re-use threads.
|
||||
*
|
||||
* <p>As of 5.0 this executor is also used when a controller returns a reactive
|
||||
* type that does streaming (e.g. "text/event-stream" or
|
||||
* "application/stream+json") for the blocking writes to the
|
||||
* {@link javax.servlet.ServletOutputStream}.
|
||||
*
|
||||
* @param taskExecutor the task executor instance to use by default
|
||||
*/
|
||||
public AsyncSupportConfigurer setTaskExecutor(AsyncTaskExecutor taskExecutor) {
|
||||
@@ -75,7 +71,6 @@ public class AsyncSupportConfigurer {
|
||||
* for further processing of the concurrently produced result.
|
||||
* <p>If this value is not set, the default timeout of the underlying
|
||||
* implementation is used, e.g. 10 seconds on Tomcat with Servlet 3.
|
||||
*
|
||||
* @param timeout the timeout value in milliseconds
|
||||
*/
|
||||
public AsyncSupportConfigurer setDefaultTimeout(long timeout) {
|
||||
@@ -87,11 +82,9 @@ public class AsyncSupportConfigurer {
|
||||
* Configure lifecycle interceptors with callbacks around concurrent request
|
||||
* execution that starts when a controller returns a
|
||||
* {@link java.util.concurrent.Callable}.
|
||||
*
|
||||
* @param interceptors the interceptors to register
|
||||
*/
|
||||
public AsyncSupportConfigurer registerCallableInterceptors(CallableProcessingInterceptor... interceptors) {
|
||||
Assert.notNull(interceptors, "Interceptors are required");
|
||||
this.callableInterceptors.addAll(Arrays.asList(interceptors));
|
||||
return this;
|
||||
}
|
||||
@@ -99,19 +92,20 @@ public class AsyncSupportConfigurer {
|
||||
/**
|
||||
* Configure lifecycle interceptors with callbacks around concurrent request
|
||||
* execution that starts when a controller returns a {@link DeferredResult}.
|
||||
*
|
||||
* @param interceptors the interceptors to register
|
||||
*/
|
||||
public AsyncSupportConfigurer registerDeferredResultInterceptors(DeferredResultProcessingInterceptor... interceptors) {
|
||||
Assert.notNull(interceptors, "Interceptors are required");
|
||||
this.deferredResultInterceptors.addAll(Arrays.asList(interceptors));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
protected AsyncTaskExecutor getTaskExecutor() {
|
||||
return this.taskExecutor;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected Long getTimeout() {
|
||||
return this.timeout;
|
||||
}
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2014 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.servlet.config.annotation;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.context.annotation.ConfigurationCondition;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* A simple configuration condition that checks for the absence of any beans
|
||||
* of a given type.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 4.1
|
||||
*/
|
||||
class BeanTypeNotPresentCondition implements ConfigurationCondition {
|
||||
|
||||
private static final Log logger =
|
||||
LogFactory.getLog("org.springframework.web.servlet.config.annotation.ViewResolution");
|
||||
|
||||
private final Class<?> beanType;
|
||||
|
||||
|
||||
BeanTypeNotPresentCondition(Class<?> beanType) {
|
||||
this.beanType = beanType;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ConfigurationPhase getConfigurationPhase() {
|
||||
return ConfigurationPhase.PARSE_CONFIGURATION;
|
||||
}
|
||||
|
||||
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
ListableBeanFactory factory = context.getBeanFactory();
|
||||
String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(factory, this.beanType, false, false);
|
||||
if (ObjectUtils.isEmpty(names)) {
|
||||
logger.debug("No bean of type [" + this.beanType + "]. Conditional configuration applies.");
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
logger.debug("Found bean of type [" + this.beanType + "]. Conditional configuration does not apply.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,16 +13,17 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.servlet.config.annotation;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.MediaTypeFactory;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.web.accept.ContentNegotiationManager;
|
||||
import org.springframework.web.accept.ContentNegotiationManagerFactoryBean;
|
||||
import org.springframework.web.accept.ContentNegotiationStrategy;
|
||||
@@ -39,34 +40,34 @@ import org.springframework.web.accept.PathExtensionContentNegotiationStrategy;
|
||||
*
|
||||
* <table>
|
||||
* <tr>
|
||||
* <th>Configurer Property</th>
|
||||
* <th>Underlying Strategy</th>
|
||||
* <th>Default Setting</th>
|
||||
* <th>Configurer Property</th>
|
||||
* <th>Underlying Strategy</th>
|
||||
* <th>Default Setting</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@link #favorPathExtension}</td>
|
||||
* <td>{@link PathExtensionContentNegotiationStrategy Path Extension strategy}</td>
|
||||
* <td>On</td>
|
||||
* <td>{@link #favorPathExtension}</td>
|
||||
* <td>{@link PathExtensionContentNegotiationStrategy Path Extension strategy}</td>
|
||||
* <td>On</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@link #favorParameter}</td>
|
||||
* <td>{@link ParameterContentNegotiationStrategy Parameter strategy}</td>
|
||||
* <td>Off</td>
|
||||
* <td>{@link #favorParameter}</td>
|
||||
* <td>{@link ParameterContentNegotiationStrategy Parameter strategy}</td>
|
||||
* <td>Off</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@link #ignoreAcceptHeader}</td>
|
||||
* <td>{@link HeaderContentNegotiationStrategy Header strategy}</td>
|
||||
* <td>On</td>
|
||||
* <td>{@link #ignoreAcceptHeader}</td>
|
||||
* <td>{@link HeaderContentNegotiationStrategy Header strategy}</td>
|
||||
* <td>On</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@link #defaultContentType}</td>
|
||||
* <td>{@link FixedContentNegotiationStrategy Fixed content strategy}</td>
|
||||
* <td>Not set</td>
|
||||
* <td>{@link #defaultContentType}</td>
|
||||
* <td>{@link FixedContentNegotiationStrategy Fixed content strategy}</td>
|
||||
* <td>Not set</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@link #defaultContentTypeStrategy}</td>
|
||||
* <td>{@link ContentNegotiationStrategy}</td>
|
||||
* <td>Not set</td>
|
||||
* <td>{@link #defaultContentTypeStrategy}</td>
|
||||
* <td>{@link ContentNegotiationStrategy}</td>
|
||||
* <td>Not set</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
@@ -87,8 +88,7 @@ import org.springframework.web.accept.PathExtensionContentNegotiationStrategy;
|
||||
*/
|
||||
public class ContentNegotiationConfigurer {
|
||||
|
||||
private final ContentNegotiationManagerFactoryBean factory =
|
||||
new ContentNegotiationManagerFactoryBean();
|
||||
private final ContentNegotiationManagerFactoryBean factory = new ContentNegotiationManagerFactoryBean();
|
||||
|
||||
private final Map<String, MediaType> mediaTypes = new HashMap<>();
|
||||
|
||||
@@ -138,7 +138,7 @@ public class ContentNegotiationConfigurer {
|
||||
* @see #mediaType(String, MediaType)
|
||||
* @see #replaceMediaTypes(Map)
|
||||
*/
|
||||
public ContentNegotiationConfigurer mediaTypes(Map<String, MediaType> mediaTypes) {
|
||||
public ContentNegotiationConfigurer mediaTypes(@Nullable Map<String, MediaType> mediaTypes) {
|
||||
if (mediaTypes != null) {
|
||||
this.mediaTypes.putAll(mediaTypes);
|
||||
}
|
||||
@@ -221,12 +221,9 @@ public class ContentNegotiationConfigurer {
|
||||
/**
|
||||
* Set the default content type(s) to use when no content type is requested
|
||||
* in order of priority.
|
||||
*
|
||||
* <p>If destinations are present that do not support any of the given media
|
||||
* types, consider appending {@link MediaType#ALL} at the end.
|
||||
*
|
||||
* <p>By default this is not set.
|
||||
*
|
||||
* @see #defaultContentTypeStrategy
|
||||
*/
|
||||
public ContentNegotiationConfigurer defaultContentType(MediaType... defaultContentTypes) {
|
||||
@@ -246,10 +243,10 @@ public class ContentNegotiationConfigurer {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
protected ContentNegotiationManager getContentNegotiationManager() throws Exception {
|
||||
this.factory.addMediaTypes(this.mediaTypes);
|
||||
this.factory.afterPropertiesSet();
|
||||
return this.factory.getObject();
|
||||
return this.factory.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -18,7 +18,6 @@ package org.springframework.web.servlet.config.annotation;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -30,15 +29,18 @@ import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
|
||||
import org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler;
|
||||
|
||||
/**
|
||||
* Configures a request handler for serving static resources by forwarding the request to the Servlet container's
|
||||
* "default" Servlet. This is intended to be used when the Spring MVC {@link DispatcherServlet} is mapped to "/"
|
||||
* thus overriding the Servlet container's default handling of static resources. Since this handler is configured
|
||||
* at the lowest precedence, effectively it allows all other handler mappings to handle the request, and if none
|
||||
* Configures a request handler for serving static resources by forwarding
|
||||
* the request to the Servlet container's "default" Servlet. This is intended
|
||||
* to be used when the Spring MVC {@link DispatcherServlet} is mapped to "/"
|
||||
* thus overriding the Servlet container's default handling of static resources.
|
||||
*
|
||||
* <p>Since this handler is configured at the lowest precedence, effectively
|
||||
* it allows all other handler mappings to handle the request, and if none
|
||||
* of them do, this handler can forward it to the "default" Servlet.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*
|
||||
* @see DefaultServletHttpRequestHandler
|
||||
*/
|
||||
public class DefaultServletHandlerConfigurer {
|
||||
@@ -47,19 +49,22 @@ public class DefaultServletHandlerConfigurer {
|
||||
|
||||
private DefaultServletHttpRequestHandler handler;
|
||||
|
||||
|
||||
/**
|
||||
* Create a {@link DefaultServletHandlerConfigurer} instance.
|
||||
* @param servletContext the ServletContext to use to configure the underlying DefaultServletHttpRequestHandler.
|
||||
* @param servletContext the ServletContext to use.
|
||||
*/
|
||||
public DefaultServletHandlerConfigurer(ServletContext servletContext) {
|
||||
Assert.notNull(servletContext, "A ServletContext is required to configure default servlet handling");
|
||||
Assert.notNull(servletContext, "ServletContext is required");
|
||||
this.servletContext = servletContext;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Enable forwarding to the "default" Servlet. When this method is used the {@link DefaultServletHttpRequestHandler}
|
||||
* will try to auto-detect the "default" Servlet name. Alternatively, you can specify the name of the default
|
||||
* Servlet via {@link #enable(String)}.
|
||||
* Enable forwarding to the "default" Servlet.
|
||||
* <p>When this method is used the {@link DefaultServletHttpRequestHandler}
|
||||
* will try to autodetect the "default" Servlet name. Alternatively, you can
|
||||
* specify the name of the default Servlet via {@link #enable(String)}.
|
||||
* @see DefaultServletHttpRequestHandler
|
||||
*/
|
||||
public void enable() {
|
||||
@@ -68,28 +73,31 @@ public class DefaultServletHandlerConfigurer {
|
||||
|
||||
/**
|
||||
* Enable forwarding to the "default" Servlet identified by the given name.
|
||||
* This is useful when the default Servlet cannot be auto-detected, for example when it has been manually configured.
|
||||
* <p>This is useful when the default Servlet cannot be autodetected,
|
||||
* for example when it has been manually configured.
|
||||
* @see DefaultServletHttpRequestHandler
|
||||
*/
|
||||
public void enable(@Nullable String defaultServletName) {
|
||||
handler = new DefaultServletHttpRequestHandler();
|
||||
handler.setDefaultServletName(defaultServletName);
|
||||
handler.setServletContext(servletContext);
|
||||
this.handler = new DefaultServletHttpRequestHandler();
|
||||
if (defaultServletName != null) {
|
||||
this.handler.setDefaultServletName(defaultServletName);
|
||||
}
|
||||
this.handler.setServletContext(this.servletContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a handler mapping instance ordered at {@link Integer#MAX_VALUE} containing the
|
||||
* {@link DefaultServletHttpRequestHandler} instance mapped to {@code "/**"}; or {@code null} if
|
||||
* default servlet handling was not been enabled.
|
||||
* {@link DefaultServletHttpRequestHandler} instance mapped to {@code "/**"};
|
||||
* or {@code null} if default servlet handling was not been enabled.
|
||||
*/
|
||||
@Nullable
|
||||
protected AbstractHandlerMapping getHandlerMapping() {
|
||||
if (handler == null) {
|
||||
if (this.handler == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Map<String, HttpRequestHandler> urlMap = new HashMap<>();
|
||||
urlMap.put("/**", handler);
|
||||
urlMap.put("/**", this.handler);
|
||||
|
||||
SimpleUrlHandlerMapping handlerMapping = new SimpleUrlHandlerMapping();
|
||||
handlerMapping.setOrder(Integer.MAX_VALUE);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -21,8 +21,8 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.PathMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import org.springframework.web.servlet.handler.MappedInterceptor;
|
||||
|
||||
@@ -88,8 +88,8 @@ public class InterceptorRegistration {
|
||||
return this.interceptor;
|
||||
}
|
||||
|
||||
String[] include = toArray(this.includePatterns);
|
||||
String[] exclude = toArray(this.excludePatterns);
|
||||
String[] include = StringUtils.toStringArray(this.includePatterns);
|
||||
String[] exclude = StringUtils.toStringArray(this.excludePatterns);
|
||||
MappedInterceptor mappedInterceptor = new MappedInterceptor(include, exclude, this.interceptor);
|
||||
|
||||
if (this.pathMatcher != null) {
|
||||
@@ -99,8 +99,4 @@ public class InterceptorRegistration {
|
||||
return mappedInterceptor;
|
||||
}
|
||||
|
||||
private static String[] toArray(List<String> list) {
|
||||
return (CollectionUtils.isEmpty(list) ? null : list.toArray(new String[list.size()]));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,13 +28,13 @@ import org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapt
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Keith Donald
|
||||
*
|
||||
* @since 3.1
|
||||
*/
|
||||
public class InterceptorRegistry {
|
||||
|
||||
private final List<InterceptorRegistration> registrations = new ArrayList<>();
|
||||
|
||||
|
||||
/**
|
||||
* Adds the provided {@link HandlerInterceptor}.
|
||||
* @param interceptor the interceptor to add
|
||||
@@ -43,7 +43,7 @@ public class InterceptorRegistry {
|
||||
*/
|
||||
public InterceptorRegistration addInterceptor(HandlerInterceptor interceptor) {
|
||||
InterceptorRegistration registration = new InterceptorRegistration(interceptor);
|
||||
registrations.add(registration);
|
||||
this.registrations.add(registration);
|
||||
return registration;
|
||||
}
|
||||
|
||||
@@ -56,16 +56,16 @@ public class InterceptorRegistry {
|
||||
public InterceptorRegistration addWebRequestInterceptor(WebRequestInterceptor interceptor) {
|
||||
WebRequestHandlerInterceptorAdapter adapted = new WebRequestHandlerInterceptorAdapter(interceptor);
|
||||
InterceptorRegistration registration = new InterceptorRegistration(adapted);
|
||||
registrations.add(registration);
|
||||
this.registrations.add(registration);
|
||||
return registration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all registered interceptors.
|
||||
* Return all registered interceptors.
|
||||
*/
|
||||
protected List<Object> getInterceptors() {
|
||||
List<Object> interceptors = new ArrayList<>();
|
||||
for (InterceptorRegistration registration : registrations) {
|
||||
List<Object> interceptors = new ArrayList<>(this.registrations.size());
|
||||
for (InterceptorRegistration registration : this.registrations) {
|
||||
interceptors.add(registration.getInterceptor());
|
||||
}
|
||||
return interceptors ;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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,6 +16,7 @@
|
||||
|
||||
package org.springframework.web.servlet.config.annotation;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.PathMatcher;
|
||||
import org.springframework.web.util.UrlPathHelper;
|
||||
import org.springframework.web.util.pattern.ParsingPathMatcher;
|
||||
@@ -107,26 +108,30 @@ public class PathMatchConfigurer {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
public Boolean isUseSuffixPatternMatch() {
|
||||
return this.suffixPatternMatch;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Boolean isUseTrailingSlashMatch() {
|
||||
return this.trailingSlashMatch;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Boolean isUseRegisteredSuffixPatternMatch() {
|
||||
return this.registeredSuffixPatternMatch;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public UrlPathHelper getUrlPathHelper() {
|
||||
return this.urlPathHelper;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PathMatcher getPathMatcher() {
|
||||
if(this.pathMatcher != null
|
||||
&& this.pathMatcher.getClass().isAssignableFrom(ParsingPathMatcher.class)
|
||||
&& (this.trailingSlashMatch || this.suffixPatternMatch)) {
|
||||
if (this.pathMatcher instanceof ParsingPathMatcher && (this.trailingSlashMatch || this.suffixPatternMatch)) {
|
||||
throw new IllegalStateException("When using a ParsingPathMatcher, useTrailingSlashMatch" +
|
||||
" and useSuffixPatternMatch should be set to 'false'.");
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -21,6 +21,7 @@ import java.util.List;
|
||||
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.concurrent.ConcurrentMapCache;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.web.servlet.resource.CachingResourceResolver;
|
||||
@@ -60,10 +61,10 @@ public class ResourceChainRegistration {
|
||||
|
||||
|
||||
public ResourceChainRegistration(boolean cacheResources) {
|
||||
this(cacheResources, cacheResources ? new ConcurrentMapCache(DEFAULT_CACHE_NAME) : null);
|
||||
this(cacheResources, (cacheResources ? new ConcurrentMapCache(DEFAULT_CACHE_NAME) : null));
|
||||
}
|
||||
|
||||
public ResourceChainRegistration(boolean cacheResources, Cache cache) {
|
||||
public ResourceChainRegistration(boolean cacheResources, @Nullable Cache cache) {
|
||||
Assert.isTrue(!cacheResources || cache != null, "'cache' is required when cacheResources=true");
|
||||
if (cacheResources) {
|
||||
this.resolvers.add(new CachingResourceResolver(cache));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -21,7 +21,6 @@ import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.springframework.beans.factory.BeanInitializationException;
|
||||
@@ -81,7 +80,7 @@ public class ResourceHandlerRegistry {
|
||||
* @since 4.3
|
||||
*/
|
||||
public ResourceHandlerRegistry(ApplicationContext applicationContext, ServletContext servletContext,
|
||||
ContentNegotiationManager contentNegotiationManager) {
|
||||
@Nullable ContentNegotiationManager contentNegotiationManager) {
|
||||
|
||||
Assert.notNull(applicationContext, "ApplicationContext is required");
|
||||
this.applicationContext = applicationContext;
|
||||
|
||||
@@ -22,7 +22,6 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
@@ -258,32 +257,37 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
|
||||
*/
|
||||
@Bean
|
||||
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
|
||||
RequestMappingHandlerMapping handlerMapping = createRequestMappingHandlerMapping();
|
||||
handlerMapping.setOrder(0);
|
||||
handlerMapping.setInterceptors(getInterceptors());
|
||||
handlerMapping.setContentNegotiationManager(mvcContentNegotiationManager());
|
||||
handlerMapping.setCorsConfigurations(getCorsConfigurations());
|
||||
RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
|
||||
mapping.setOrder(0);
|
||||
mapping.setInterceptors(getInterceptors());
|
||||
mapping.setContentNegotiationManager(mvcContentNegotiationManager());
|
||||
mapping.setCorsConfigurations(getCorsConfigurations());
|
||||
|
||||
PathMatchConfigurer configurer = getPathMatchConfigurer();
|
||||
if (configurer.isUseSuffixPatternMatch() != null) {
|
||||
handlerMapping.setUseSuffixPatternMatch(configurer.isUseSuffixPatternMatch());
|
||||
Boolean useSuffixPatternMatch = configurer.isUseSuffixPatternMatch();
|
||||
Boolean useRegisteredSuffixPatternMatch = configurer.isUseRegisteredSuffixPatternMatch();
|
||||
Boolean useTrailingSlashMatch = configurer.isUseTrailingSlashMatch();
|
||||
if (useSuffixPatternMatch != null) {
|
||||
mapping.setUseSuffixPatternMatch(useSuffixPatternMatch);
|
||||
}
|
||||
if (configurer.isUseRegisteredSuffixPatternMatch() != null) {
|
||||
handlerMapping.setUseRegisteredSuffixPatternMatch(configurer.isUseRegisteredSuffixPatternMatch());
|
||||
if (useRegisteredSuffixPatternMatch != null) {
|
||||
mapping.setUseRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch);
|
||||
}
|
||||
if (configurer.isUseTrailingSlashMatch() != null) {
|
||||
handlerMapping.setUseTrailingSlashMatch(configurer.isUseTrailingSlashMatch());
|
||||
}
|
||||
UrlPathHelper pathHelper = configurer.getUrlPathHelper();
|
||||
if (pathHelper != null) {
|
||||
handlerMapping.setUrlPathHelper(pathHelper);
|
||||
}
|
||||
PathMatcher pathMatcher = configurer.getPathMatcher();
|
||||
if (pathMatcher != null) {
|
||||
handlerMapping.setPathMatcher(pathMatcher);
|
||||
if (useTrailingSlashMatch != null) {
|
||||
mapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
|
||||
}
|
||||
|
||||
return handlerMapping;
|
||||
UrlPathHelper pathHelper = configurer.getUrlPathHelper();
|
||||
if (pathHelper != null) {
|
||||
mapping.setUrlPathHelper(pathHelper);
|
||||
}
|
||||
|
||||
PathMatcher pathMatcher = configurer.getPathMatcher();
|
||||
if (pathMatcher != null) {
|
||||
mapping.setPathMatcher(pathMatcher);
|
||||
}
|
||||
|
||||
return mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -579,7 +583,10 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
|
||||
ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
|
||||
initializer.setConversionService(mvcConversionService());
|
||||
initializer.setValidator(mvcValidator());
|
||||
initializer.setMessageCodesResolver(getMessageCodesResolver());
|
||||
MessageCodesResolver messageCodesResolver = getMessageCodesResolver();
|
||||
if (messageCodesResolver != null) {
|
||||
initializer.setMessageCodesResolver(messageCodesResolver);
|
||||
}
|
||||
return initializer;
|
||||
}
|
||||
|
||||
|
||||
@@ -55,14 +55,12 @@ public interface WebMvcConfigurer {
|
||||
* <li>ViewControllerMappings</li>
|
||||
* <li>ResourcesMappings</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>Note that if a {@link org.springframework.web.util.pattern.ParsingPathMatcher}
|
||||
* is configured here,
|
||||
* the {@link PathMatchConfigurer#setUseTrailingSlashMatch(Boolean)} and
|
||||
* {@link PathMatchConfigurer#setUseSuffixPatternMatch(Boolean)} options must be set
|
||||
* to {@literal false}as they can lead to illegal patterns,
|
||||
* see {@link org.springframework.web.util.pattern.ParsingPathMatcher}.
|
||||
*
|
||||
* @since 4.0.3
|
||||
*/
|
||||
default void configurePathMatch(PathMatchConfigurer configurer) {
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.web.servlet.handler;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextException;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
@@ -68,12 +69,13 @@ public abstract class AbstractDetectingUrlHandlerMapping extends AbstractUrlHand
|
||||
* @see #determineUrlsForHandler(String)
|
||||
*/
|
||||
protected void detectHandlers() throws BeansException {
|
||||
ApplicationContext applicationContext = obtainApplicationContext();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Looking for URL mappings in application context: " + getApplicationContext());
|
||||
logger.debug("Looking for URL mappings in application context: " + applicationContext);
|
||||
}
|
||||
String[] beanNames = (this.detectHandlersInAncestorContexts ?
|
||||
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
|
||||
getApplicationContext().getBeanNamesForType(Object.class));
|
||||
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class) :
|
||||
applicationContext.getBeanNamesForType(Object.class));
|
||||
|
||||
// Take any bean name that we can determine URLs for.
|
||||
for (String beanName : beanNames) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -21,7 +21,6 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
@@ -194,12 +193,12 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
|
||||
* <p>Supported interceptor types are HandlerInterceptor, WebRequestInterceptor, and MappedInterceptor.
|
||||
* Mapped interceptors apply only to request URLs that match its path patterns.
|
||||
* Mapped interceptor beans are also detected by type during initialization.
|
||||
* @param interceptors array of handler interceptors, or {@code null} if none
|
||||
* @param interceptors array of handler interceptors
|
||||
* @see #adaptInterceptor
|
||||
* @see org.springframework.web.servlet.HandlerInterceptor
|
||||
* @see org.springframework.web.context.request.WebRequestInterceptor
|
||||
*/
|
||||
public void setInterceptors(@Nullable Object... interceptors) {
|
||||
public void setInterceptors(Object... interceptors) {
|
||||
this.interceptors.addAll(Arrays.asList(interceptors));
|
||||
}
|
||||
|
||||
@@ -273,7 +272,7 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
|
||||
protected void detectMappedInterceptors(List<HandlerInterceptor> mappedInterceptors) {
|
||||
mappedInterceptors.addAll(
|
||||
BeanFactoryUtils.beansOfTypeIncludingAncestors(
|
||||
getApplicationContext(), MappedInterceptor.class, true, false).values());
|
||||
obtainApplicationContext(), MappedInterceptor.class, true, false).values());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -364,7 +363,7 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
|
||||
// Bean name or resolved handler?
|
||||
if (handler instanceof String) {
|
||||
String handlerName = (String) handler;
|
||||
handler = getApplicationContext().getBean(handlerName);
|
||||
handler = obtainApplicationContext().getBean(handlerName);
|
||||
}
|
||||
|
||||
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
|
||||
@@ -439,16 +438,17 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
|
||||
* Retrieve the CORS configuration for the given handler.
|
||||
* @param handler the handler to check (never {@code null}).
|
||||
* @param request the current request.
|
||||
* @return the CORS configuration for the handler or {@code null}.
|
||||
* @return the CORS configuration for the handler, or {@code null} if none
|
||||
* @since 4.2
|
||||
*/
|
||||
@Nullable
|
||||
protected CorsConfiguration getCorsConfiguration(Object handler, HttpServletRequest request) {
|
||||
Object resolvedHandler = handler;
|
||||
if (handler instanceof HandlerExecutionChain) {
|
||||
handler = ((HandlerExecutionChain) handler).getHandler();
|
||||
resolvedHandler = ((HandlerExecutionChain) handler).getHandler();
|
||||
}
|
||||
if (handler instanceof CorsConfigurationSource) {
|
||||
return ((CorsConfigurationSource) handler).getCorsConfiguration(request);
|
||||
if (resolvedHandler instanceof CorsConfigurationSource) {
|
||||
return ((CorsConfigurationSource) resolvedHandler).getCorsConfiguration(request);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -462,7 +462,7 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
|
||||
* HandlerInterceptor that makes CORS-related checks and adds CORS headers.
|
||||
* @param request the current request
|
||||
* @param chain the handler chain
|
||||
* @param config the applicable CORS configuration, possibly {@code null}
|
||||
* @param config the applicable CORS configuration (possibly {@code null})
|
||||
* @since 4.2
|
||||
*/
|
||||
protected HandlerExecutionChain getCorsHandlerExecutionChain(HttpServletRequest request,
|
||||
@@ -483,7 +483,7 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
|
||||
|
||||
private final CorsConfiguration config;
|
||||
|
||||
public PreFlightHandler(CorsConfiguration config) {
|
||||
public PreFlightHandler(@Nullable CorsConfiguration config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@@ -503,7 +503,7 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
|
||||
|
||||
private final CorsConfiguration config;
|
||||
|
||||
public CorsInterceptor(CorsConfiguration config) {
|
||||
public CorsInterceptor(@Nullable CorsConfiguration config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -41,7 +41,7 @@ public abstract class AbstractHandlerMethodExceptionResolver extends AbstractHan
|
||||
@Override
|
||||
protected boolean shouldApplyTo(HttpServletRequest request, @Nullable Object handler) {
|
||||
if (handler == null) {
|
||||
return super.shouldApplyTo(request, handler);
|
||||
return super.shouldApplyTo(request, null);
|
||||
}
|
||||
else if (handler instanceof HandlerMethod) {
|
||||
HandlerMethod handlerMethod = (HandlerMethod) handler;
|
||||
|
||||
@@ -28,7 +28,6 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
@@ -199,14 +198,14 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
|
||||
logger.debug("Looking for request mappings in application context: " + getApplicationContext());
|
||||
}
|
||||
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
|
||||
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
|
||||
getApplicationContext().getBeanNamesForType(Object.class));
|
||||
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) :
|
||||
obtainApplicationContext().getBeanNamesForType(Object.class));
|
||||
|
||||
for (String beanName : beanNames) {
|
||||
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
|
||||
Class<?> beanType = null;
|
||||
try {
|
||||
beanType = getApplicationContext().getType(beanName);
|
||||
beanType = obtainApplicationContext().getType(beanName);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
|
||||
@@ -228,13 +227,12 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
|
||||
*/
|
||||
protected void detectHandlerMethods(final Object handler) {
|
||||
Class<?> handlerType = (handler instanceof String ?
|
||||
getApplicationContext().getType((String) handler) : handler.getClass());
|
||||
final Class<?> userType = ClassUtils.getUserClass(handlerType);
|
||||
obtainApplicationContext().getType((String) handler) : handler.getClass());
|
||||
|
||||
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
|
||||
new MethodIntrospector.MetadataLookup<T>() {
|
||||
@Override
|
||||
public T inspect(Method method) {
|
||||
if (handlerType != null) {
|
||||
final Class<?> userType = ClassUtils.getUserClass(handlerType);
|
||||
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
|
||||
(MethodIntrospector.MetadataLookup<T>) method -> {
|
||||
try {
|
||||
return getMappingForMethod(method, userType);
|
||||
}
|
||||
@@ -242,16 +240,15 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
|
||||
throw new IllegalStateException("Invalid mapping on handler class [" +
|
||||
userType.getName() + "]: " + method, ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
|
||||
}
|
||||
for (Map.Entry<Method, T> entry : methods.entrySet()) {
|
||||
Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
|
||||
T mapping = entry.getValue();
|
||||
registerHandlerMethod(handler, invocableMethod, mapping);
|
||||
});
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
|
||||
}
|
||||
for (Map.Entry<Method, T> entry : methods.entrySet()) {
|
||||
Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
|
||||
T mapping = entry.getValue();
|
||||
registerHandlerMethod(handler, invocableMethod, mapping);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,7 +276,7 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
|
||||
if (handler instanceof String) {
|
||||
String beanName = (String) handler;
|
||||
handlerMethod = new HandlerMethod(beanName,
|
||||
getApplicationContext().getAutowireCapableBeanFactory(), method);
|
||||
obtainApplicationContext().getAutowireCapableBeanFactory(), method);
|
||||
}
|
||||
else {
|
||||
handlerMethod = new HandlerMethod(handler, method);
|
||||
@@ -507,6 +504,7 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
|
||||
* Return matches for the given URL path. Not thread-safe.
|
||||
* @see #acquireReadLock()
|
||||
*/
|
||||
@Nullable
|
||||
public List<T> getMappingsByUrl(String urlPath) {
|
||||
return this.urlLookup.get(urlPath);
|
||||
}
|
||||
@@ -687,7 +685,9 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
|
||||
|
||||
private final String mappingName;
|
||||
|
||||
public MappingRegistration(T mapping, HandlerMethod handlerMethod, List<String> directUrls, String mappingName) {
|
||||
public MappingRegistration(T mapping, HandlerMethod handlerMethod,
|
||||
@Nullable List<String> directUrls, @Nullable String mappingName) {
|
||||
|
||||
Assert.notNull(mapping, "Mapping must not be null");
|
||||
Assert.notNull(handlerMethod, "HandlerMethod must not be null");
|
||||
this.mapping = mapping;
|
||||
@@ -708,6 +708,7 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
|
||||
return this.directUrls;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getMappingName() {
|
||||
return this.mappingName;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
@@ -134,7 +135,7 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping i
|
||||
// Bean name or resolved handler?
|
||||
if (rawHandler instanceof String) {
|
||||
String handlerName = (String) rawHandler;
|
||||
rawHandler = getApplicationContext().getBean(handlerName);
|
||||
rawHandler = obtainApplicationContext().getBean(handlerName);
|
||||
}
|
||||
validateHandler(rawHandler, request);
|
||||
handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
|
||||
@@ -170,7 +171,7 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping i
|
||||
// Bean name or resolved handler?
|
||||
if (handler instanceof String) {
|
||||
String handlerName = (String) handler;
|
||||
handler = getApplicationContext().getBean(handlerName);
|
||||
handler = obtainApplicationContext().getBean(handlerName);
|
||||
}
|
||||
validateHandler(handler, request);
|
||||
return buildPathExposingHandler(handler, urlPath, urlPath, null);
|
||||
@@ -212,7 +213,7 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping i
|
||||
// Bean name or resolved handler?
|
||||
if (handler instanceof String) {
|
||||
String handlerName = (String) handler;
|
||||
handler = getApplicationContext().getBean(handlerName);
|
||||
handler = obtainApplicationContext().getBean(handlerName);
|
||||
}
|
||||
validateHandler(handler, request);
|
||||
String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestMatch, urlPath);
|
||||
@@ -335,8 +336,9 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping i
|
||||
// Eagerly resolve handler if referencing singleton via name.
|
||||
if (!this.lazyInitHandlers && handler instanceof String) {
|
||||
String handlerName = (String) handler;
|
||||
if (getApplicationContext().isSingleton(handlerName)) {
|
||||
resolvedHandler = getApplicationContext().getBean(handlerName);
|
||||
ApplicationContext applicationContext = obtainApplicationContext();
|
||||
if (applicationContext.isSingleton(handlerName)) {
|
||||
resolvedHandler = applicationContext.getBean(handlerName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ public class BeanNameUrlHandlerMapping extends AbstractDetectingUrlHandlerMappin
|
||||
if (beanName.startsWith("/")) {
|
||||
urls.add(beanName);
|
||||
}
|
||||
String[] aliases = getApplicationContext().getAliases(beanName);
|
||||
String[] aliases = obtainApplicationContext().getAliases(beanName);
|
||||
for (String alias : aliases) {
|
||||
if (alias.startsWith("/")) {
|
||||
urls.add(alias);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -20,6 +20,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.PathMatcher;
|
||||
import org.springframework.web.context.request.WebRequestInterceptor;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
@@ -68,7 +69,9 @@ public final class MappedInterceptor implements HandlerInterceptor {
|
||||
* @param excludePatterns the path patterns to exclude
|
||||
* @param interceptor the HandlerInterceptor instance to map to the given patterns
|
||||
*/
|
||||
public MappedInterceptor(@Nullable String[] includePatterns, String[] excludePatterns, HandlerInterceptor interceptor) {
|
||||
public MappedInterceptor(@Nullable String[] includePatterns, @Nullable String[] excludePatterns,
|
||||
HandlerInterceptor interceptor) {
|
||||
|
||||
this.includePatterns = includePatterns;
|
||||
this.excludePatterns = excludePatterns;
|
||||
this.interceptor = interceptor;
|
||||
@@ -89,7 +92,9 @@ public final class MappedInterceptor implements HandlerInterceptor {
|
||||
* @param includePatterns the path patterns to map with a {@code null} value matching to all paths
|
||||
* @param interceptor the WebRequestInterceptor instance to map to the given patterns
|
||||
*/
|
||||
public MappedInterceptor(@Nullable String[] includePatterns, String[] excludePatterns, WebRequestInterceptor interceptor) {
|
||||
public MappedInterceptor(@Nullable String[] includePatterns, @Nullable String[] excludePatterns,
|
||||
WebRequestInterceptor interceptor) {
|
||||
|
||||
this(includePatterns, excludePatterns, new WebRequestHandlerInterceptorAdapter(interceptor));
|
||||
}
|
||||
|
||||
@@ -100,8 +105,6 @@ public final class MappedInterceptor implements HandlerInterceptor {
|
||||
* method. This is an advanced property that is only required when using custom
|
||||
* PathMatcher implementations that support mapping metadata other than the
|
||||
* Ant-style path patterns supported by default.
|
||||
*
|
||||
* @param pathMatcher the path matcher to use
|
||||
*/
|
||||
public void setPathMatcher(PathMatcher pathMatcher) {
|
||||
this.pathMatcher = pathMatcher;
|
||||
@@ -135,12 +138,18 @@ public final class MappedInterceptor implements HandlerInterceptor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
|
||||
public void postHandle(
|
||||
HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView)
|
||||
throws Exception {
|
||||
|
||||
this.interceptor.postHandle(request, response, handler, modelAndView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
|
||||
public void afterCompletion(
|
||||
HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex)
|
||||
throws Exception {
|
||||
|
||||
this.interceptor.afterCompletion(request, response, handler, ex);
|
||||
}
|
||||
|
||||
@@ -158,7 +167,7 @@ public final class MappedInterceptor implements HandlerInterceptor {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.includePatterns == null) {
|
||||
if (ObjectUtils.isEmpty(this.includePatterns)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -26,6 +26,7 @@ import javax.servlet.ServletException;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanInitializationException;
|
||||
import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.web.context.ServletConfigAware;
|
||||
import org.springframework.web.context.ServletContextAware;
|
||||
|
||||
@@ -157,6 +158,7 @@ public class SimpleServletPostProcessor implements
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String getInitParameter(String paramName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 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.
|
||||
@@ -60,7 +60,8 @@ public abstract class AbstractLocaleContextResolver extends AbstractLocaleResolv
|
||||
|
||||
@Override
|
||||
public Locale resolveLocale(HttpServletRequest request) {
|
||||
return resolveLocaleContext(request).getLocale();
|
||||
Locale locale = resolveLocaleContext(request).getLocale();
|
||||
return (locale != null ? locale : request.getLocale());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -53,7 +53,7 @@ public class AcceptHeaderLocaleResolver implements LocaleResolver {
|
||||
* @param locales the supported locales
|
||||
* @since 4.3
|
||||
*/
|
||||
public void setSupportedLocales(List<Locale> locales) {
|
||||
public void setSupportedLocales(@Nullable List<Locale> locales) {
|
||||
this.supportedLocales.clear();
|
||||
if (locales != null) {
|
||||
this.supportedLocales.addAll(locales);
|
||||
|
||||
@@ -18,7 +18,6 @@ package org.springframework.web.servlet.i18n;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
@@ -260,6 +259,7 @@ public class CookieLocaleResolver extends CookieGenerator implements LocaleConte
|
||||
* @return the corresponding {@code Locale} instance
|
||||
* @since 4.3
|
||||
*/
|
||||
@Nullable
|
||||
protected Locale parseLocaleValue(String locale) {
|
||||
return (isLanguageTagCompliant() ? Locale.forLanguageTag(locale) : StringUtils.parseLocaleString(locale));
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -24,6 +24,7 @@ import javax.servlet.http.HttpServletResponse;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.servlet.LocaleResolver;
|
||||
@@ -182,6 +183,7 @@ public class LocaleChangeInterceptor extends HandlerInterceptorAdapter {
|
||||
* @return the corresponding {@code Locale} instance
|
||||
* @since 4.3
|
||||
*/
|
||||
@Nullable
|
||||
protected Locale parseLocaleValue(String locale) {
|
||||
return (isLanguageTagCompliant() ? Locale.forLanguageTag(locale) : StringUtils.parseLocaleString(locale));
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -17,11 +17,13 @@
|
||||
package org.springframework.web.servlet.mvc;
|
||||
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.util.WebUtils;
|
||||
|
||||
@@ -117,10 +119,13 @@ public class ServletForwardingController extends AbstractController implements B
|
||||
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
|
||||
throws Exception {
|
||||
|
||||
RequestDispatcher rd = getServletContext().getNamedDispatcher(this.servletName);
|
||||
ServletContext servletContext = getServletContext();
|
||||
Assert.state(servletContext != null, "No ServletContext");
|
||||
RequestDispatcher rd = servletContext.getNamedDispatcher(this.servletName);
|
||||
if (rd == null) {
|
||||
throw new ServletException("No servlet with name '" + this.servletName + "' defined in web.xml");
|
||||
}
|
||||
|
||||
// If already included, include again, else forward.
|
||||
if (useInclude(request, response)) {
|
||||
rd.include(request, response);
|
||||
@@ -136,6 +141,7 @@ public class ServletForwardingController extends AbstractController implements B
|
||||
"] in ServletForwardingController '" + this.beanName + "'");
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -27,6 +27,7 @@ import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
@@ -183,6 +184,7 @@ public class ServletWrappingController extends AbstractController
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public ServletContext getServletContext() {
|
||||
return ServletWrappingController.this.getServletContext();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -20,6 +20,7 @@ import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.servlet.HandlerMapping;
|
||||
|
||||
@@ -60,7 +61,7 @@ public class UrlFilenameViewController extends AbstractUrlViewController {
|
||||
* Set the prefix to prepend to the request URL filename
|
||||
* to build a view name.
|
||||
*/
|
||||
public void setPrefix(String prefix) {
|
||||
public void setPrefix(@Nullable String prefix) {
|
||||
this.prefix = (prefix != null ? prefix : "");
|
||||
}
|
||||
|
||||
@@ -75,7 +76,7 @@ public class UrlFilenameViewController extends AbstractUrlViewController {
|
||||
* Set the suffix to append to the request URL filename
|
||||
* to build a view name.
|
||||
*/
|
||||
public void setSuffix(String suffix) {
|
||||
public void setSuffix(@Nullable String suffix) {
|
||||
this.suffix = (suffix != null ? suffix : "");
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.web.servlet.mvc.annotation;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.ui.ExtendedModelMap;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
@@ -52,7 +53,7 @@ public interface ModelAndViewResolver {
|
||||
ModelAndView UNRESOLVED = new ModelAndView();
|
||||
|
||||
|
||||
ModelAndView resolveModelAndView(Method handlerMethod, Class<?> handlerType, Object returnValue,
|
||||
ExtendedModelMap implicitModel, NativeWebRequest webRequest);
|
||||
ModelAndView resolveModelAndView(Method handlerMethod, Class<?> handlerType,
|
||||
@Nullable Object returnValue, ExtendedModelMap implicitModel, NativeWebRequest webRequest);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -20,6 +20,7 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
/**
|
||||
@@ -73,7 +74,7 @@ abstract class AbstractMediaTypeExpression implements MediaTypeExpression, Compa
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -35,6 +35,7 @@ abstract class AbstractNameValueExpression<T> implements NameValueExpression<T>
|
||||
|
||||
protected final boolean isNegated;
|
||||
|
||||
|
||||
AbstractNameValueExpression(String expression) {
|
||||
int separator = expression.indexOf('=');
|
||||
if (separator == -1) {
|
||||
@@ -49,6 +50,7 @@ abstract class AbstractNameValueExpression<T> implements NameValueExpression<T>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
@@ -64,10 +66,6 @@ abstract class AbstractNameValueExpression<T> implements NameValueExpression<T>
|
||||
return this.isNegated;
|
||||
}
|
||||
|
||||
protected abstract boolean isCaseSensitiveName();
|
||||
|
||||
protected abstract T parseValue(String valueExpression);
|
||||
|
||||
public final boolean match(HttpServletRequest request) {
|
||||
boolean isMatch;
|
||||
if (this.value != null) {
|
||||
@@ -76,23 +74,29 @@ abstract class AbstractNameValueExpression<T> implements NameValueExpression<T>
|
||||
else {
|
||||
isMatch = matchName(request);
|
||||
}
|
||||
return isNegated ? !isMatch : isMatch;
|
||||
return (this.isNegated ? !isMatch : isMatch);
|
||||
}
|
||||
|
||||
|
||||
protected abstract boolean isCaseSensitiveName();
|
||||
|
||||
protected abstract T parseValue(String valueExpression);
|
||||
|
||||
protected abstract boolean matchName(HttpServletRequest request);
|
||||
|
||||
protected abstract boolean matchValue(HttpServletRequest request);
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj != null && obj instanceof AbstractNameValueExpression) {
|
||||
if (obj instanceof AbstractNameValueExpression) {
|
||||
AbstractNameValueExpression<?> other = (AbstractNameValueExpression<?>) obj;
|
||||
String thisName = isCaseSensitiveName() ? this.name : this.name.toLowerCase();
|
||||
String otherName = isCaseSensitiveName() ? other.name : other.name.toLowerCase();
|
||||
return ((thisName.equalsIgnoreCase(otherName)) &&
|
||||
String thisName = (isCaseSensitiveName() ? this.name : this.name.toLowerCase());
|
||||
String otherName = (isCaseSensitiveName() ? other.name : other.name.toLowerCase());
|
||||
return (thisName.equalsIgnoreCase(otherName) &&
|
||||
(this.value != null ? this.value.equals(other.value) : other.value == null) &&
|
||||
this.isNegated == other.isNegated);
|
||||
}
|
||||
@@ -101,28 +105,28 @@ abstract class AbstractNameValueExpression<T> implements NameValueExpression<T>
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = isCaseSensitiveName() ? name.hashCode() : name.toLowerCase().hashCode();
|
||||
result = 31 * result + (value != null ? value.hashCode() : 0);
|
||||
result = 31 * result + (isNegated ? 1 : 0);
|
||||
int result = (isCaseSensitiveName() ? this.name.hashCode() : this.name.toLowerCase().hashCode());
|
||||
result = 31 * result + (this.value != null ? this.value.hashCode() : 0);
|
||||
result = 31 * result + (this.isNegated ? 1 : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
if (value != null) {
|
||||
builder.append(name);
|
||||
if (isNegated) {
|
||||
if (this.value != null) {
|
||||
builder.append(this.name);
|
||||
if (this.isNegated) {
|
||||
builder.append('!');
|
||||
}
|
||||
builder.append('=');
|
||||
builder.append(value);
|
||||
builder.append(this.value);
|
||||
}
|
||||
else {
|
||||
if (isNegated) {
|
||||
if (this.isNegated) {
|
||||
builder.append('!');
|
||||
}
|
||||
builder.append(name);
|
||||
builder.append(this.name);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -19,6 +19,8 @@ package org.springframework.web.servlet.mvc.condition;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* A base class for {@link RequestCondition} types providing implementations of
|
||||
* {@link #equals(Object)}, {@link #hashCode()}, and {@link #toString()}.
|
||||
@@ -28,8 +30,32 @@ import java.util.Iterator;
|
||||
*/
|
||||
public abstract class AbstractRequestCondition<T extends AbstractRequestCondition<T>> implements RequestCondition<T> {
|
||||
|
||||
/**
|
||||
* Indicates whether this condition is empty, i.e. whether or not it
|
||||
* contains any discrete items.
|
||||
* @return {@code true} if empty; {@code false} otherwise
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return getContent().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the discrete items a request condition is composed of.
|
||||
* <p>For example URL patterns, HTTP request methods, param expressions, etc.
|
||||
* @return a collection of objects, never {@code null}
|
||||
*/
|
||||
protected abstract Collection<?> getContent();
|
||||
|
||||
/**
|
||||
* The notation to use when printing discrete items of content.
|
||||
* <p>For example {@code " || "} for URL patterns or {@code " && "}
|
||||
* for param expressions.
|
||||
*/
|
||||
protected abstract String getToStringInfix();
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
@@ -59,28 +85,4 @@ public abstract class AbstractRequestCondition<T extends AbstractRequestConditio
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this condition is empty, i.e. whether or not it
|
||||
* contains any discrete items.
|
||||
* @return {@code true} if empty; {@code false} otherwise
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return getContent().isEmpty();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the discrete items a request condition is composed of.
|
||||
* <p>For example URL patterns, HTTP request methods, param expressions, etc.
|
||||
* @return a collection of objects, never {@code null}
|
||||
*/
|
||||
protected abstract Collection<?> getContent();
|
||||
|
||||
/**
|
||||
* The notation to use when printing discrete items of content.
|
||||
* <p>For example {@code " || "} for URL patterns or {@code " && "}
|
||||
* for param expressions.
|
||||
*/
|
||||
protected abstract String getToStringInfix();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -51,7 +51,7 @@ public class CompositeRequestCondition extends AbstractRequestCondition<Composit
|
||||
* same number of conditions so they may be compared and combined.
|
||||
* It is acceptable to provide {@code null} conditions.
|
||||
*/
|
||||
public CompositeRequestCondition(@Nullable RequestCondition<?>... requestConditions) {
|
||||
public CompositeRequestCondition(RequestCondition<?>... requestConditions) {
|
||||
this.requestConditions = wrap(requestConditions);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.http.InvalidMediaTypeException;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.cors.CorsUtils;
|
||||
@@ -71,7 +72,7 @@ public final class ConsumesRequestCondition extends AbstractRequestCondition<Con
|
||||
* @param consumes as described in {@link RequestMapping#consumes()}
|
||||
* @param headers as described in {@link RequestMapping#headers()}
|
||||
*/
|
||||
public ConsumesRequestCondition(String[] consumes, String[] headers) {
|
||||
public ConsumesRequestCondition(String[] consumes, @Nullable String[] headers) {
|
||||
this(parseExpressions(consumes, headers));
|
||||
}
|
||||
|
||||
@@ -84,7 +85,7 @@ public final class ConsumesRequestCondition extends AbstractRequestCondition<Con
|
||||
}
|
||||
|
||||
|
||||
private static Set<ConsumeMediaTypeExpression> parseExpressions(String[] consumes, String[] headers) {
|
||||
private static Set<ConsumeMediaTypeExpression> parseExpressions(String[] consumes, @Nullable String[] headers) {
|
||||
Set<ConsumeMediaTypeExpression> result = new LinkedHashSet<>();
|
||||
if (headers != null) {
|
||||
for (String header : headers) {
|
||||
@@ -96,10 +97,8 @@ public final class ConsumesRequestCondition extends AbstractRequestCondition<Con
|
||||
}
|
||||
}
|
||||
}
|
||||
if (consumes != null) {
|
||||
for (String consume : consumes) {
|
||||
result.add(new ConsumeMediaTypeExpression(consume));
|
||||
}
|
||||
for (String consume : consumes) {
|
||||
result.add(new ConsumeMediaTypeExpression(consume));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -63,14 +63,12 @@ public final class HeadersRequestCondition extends AbstractRequestCondition<Head
|
||||
|
||||
private static Collection<HeaderExpression> parseExpressions(String... headers) {
|
||||
Set<HeaderExpression> expressions = new LinkedHashSet<>();
|
||||
if (headers != null) {
|
||||
for (String header : headers) {
|
||||
HeaderExpression expr = new HeaderExpression(header);
|
||||
if ("Accept".equalsIgnoreCase(expr.name) || "Content-Type".equalsIgnoreCase(expr.name)) {
|
||||
continue;
|
||||
}
|
||||
expressions.add(expr);
|
||||
for (String header : headers) {
|
||||
HeaderExpression expr = new HeaderExpression(header);
|
||||
if ("Accept".equalsIgnoreCase(expr.name) || "Content-Type".equalsIgnoreCase(expr.name)) {
|
||||
continue;
|
||||
}
|
||||
expressions.add(expr);
|
||||
}
|
||||
return expressions;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -54,10 +54,8 @@ public final class ParamsRequestCondition extends AbstractRequestCondition<Param
|
||||
|
||||
private static Collection<ParamExpression> parseExpressions(String... params) {
|
||||
Set<ParamExpression> expressions = new LinkedHashSet<>();
|
||||
if (params != null) {
|
||||
for (String param : params) {
|
||||
expressions.add(new ParamExpression(param));
|
||||
}
|
||||
for (String param : params) {
|
||||
expressions.add(new ParamExpression(param));
|
||||
}
|
||||
return expressions;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -25,9 +25,9 @@ import java.util.Iterator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.PathMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -61,7 +61,7 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
|
||||
* @param patterns 0 or more URL patterns; if 0 the condition will match to every request.
|
||||
*/
|
||||
public PatternsRequestCondition(String... patterns) {
|
||||
this(asList(patterns), null, null, true, true, null);
|
||||
this(Arrays.asList(patterns), null, null, true, true, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -73,10 +73,10 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
|
||||
* @param useSuffixPatternMatch whether to enable matching by suffix (".*")
|
||||
* @param useTrailingSlashMatch whether to match irrespective of a trailing slash
|
||||
*/
|
||||
public PatternsRequestCondition(String[] patterns, UrlPathHelper urlPathHelper, PathMatcher pathMatcher,
|
||||
boolean useSuffixPatternMatch, boolean useTrailingSlashMatch) {
|
||||
public PatternsRequestCondition(String[] patterns, @Nullable UrlPathHelper urlPathHelper,
|
||||
@Nullable PathMatcher pathMatcher, boolean useSuffixPatternMatch, boolean useTrailingSlashMatch) {
|
||||
|
||||
this(asList(patterns), urlPathHelper, pathMatcher, useSuffixPatternMatch, useTrailingSlashMatch, null);
|
||||
this(Arrays.asList(patterns), urlPathHelper, pathMatcher, useSuffixPatternMatch, useTrailingSlashMatch, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,25 +89,27 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
|
||||
* @param useTrailingSlashMatch whether to match irrespective of a trailing slash
|
||||
* @param fileExtensions a list of file extensions to consider for path matching
|
||||
*/
|
||||
public PatternsRequestCondition(String[] patterns, UrlPathHelper urlPathHelper,
|
||||
PathMatcher pathMatcher, boolean useSuffixPatternMatch, boolean useTrailingSlashMatch,
|
||||
List<String> fileExtensions) {
|
||||
public PatternsRequestCondition(String[] patterns, @Nullable UrlPathHelper urlPathHelper,
|
||||
@Nullable PathMatcher pathMatcher, boolean useSuffixPatternMatch,
|
||||
boolean useTrailingSlashMatch, @Nullable List<String> fileExtensions) {
|
||||
|
||||
this(asList(patterns), urlPathHelper, pathMatcher, useSuffixPatternMatch, useTrailingSlashMatch, fileExtensions);
|
||||
this(Arrays.asList(patterns), urlPathHelper, pathMatcher, useSuffixPatternMatch,
|
||||
useTrailingSlashMatch, fileExtensions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Private constructor accepting a collection of patterns.
|
||||
*/
|
||||
private PatternsRequestCondition(Collection<String> patterns, UrlPathHelper urlPathHelper,
|
||||
PathMatcher pathMatcher, boolean useSuffixPatternMatch, boolean useTrailingSlashMatch,
|
||||
List<String> fileExtensions) {
|
||||
private PatternsRequestCondition(Collection<String> patterns, @Nullable UrlPathHelper urlPathHelper,
|
||||
@Nullable PathMatcher pathMatcher, boolean useSuffixPatternMatch,
|
||||
boolean useTrailingSlashMatch, @Nullable List<String> fileExtensions) {
|
||||
|
||||
this.patterns = Collections.unmodifiableSet(prependLeadingSlash(patterns));
|
||||
this.pathHelper = (urlPathHelper != null ? urlPathHelper : new UrlPathHelper());
|
||||
this.pathMatcher = (pathMatcher != null ? pathMatcher : new AntPathMatcher());
|
||||
this.useSuffixPatternMatch = useSuffixPatternMatch;
|
||||
this.useTrailingSlashMatch = useTrailingSlashMatch;
|
||||
|
||||
if (fileExtensions != null) {
|
||||
for (String fileExtension : fileExtensions) {
|
||||
if (fileExtension.charAt(0) != '.') {
|
||||
@@ -119,14 +121,7 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
|
||||
}
|
||||
|
||||
|
||||
private static List<String> asList(String... patterns) {
|
||||
return (patterns != null ? Arrays.asList(patterns) : Collections.emptyList());
|
||||
}
|
||||
|
||||
private static Set<String> prependLeadingSlash(Collection<String> patterns) {
|
||||
if (patterns == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
Set<String> result = new LinkedHashSet<>(patterns.size());
|
||||
for (String pattern : patterns) {
|
||||
if (StringUtils.hasLength(pattern) && !pattern.startsWith("/")) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -26,6 +26,7 @@ import java.util.Set;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.web.HttpMediaTypeException;
|
||||
import org.springframework.web.HttpMediaTypeNotAcceptableException;
|
||||
import org.springframework.web.accept.ContentNegotiationManager;
|
||||
@@ -66,7 +67,7 @@ public final class ProducesRequestCondition extends AbstractRequestCondition<Pro
|
||||
* @param produces expressions with syntax defined by {@link RequestMapping#produces()}
|
||||
*/
|
||||
public ProducesRequestCondition(String... produces) {
|
||||
this(produces, (String[]) null);
|
||||
this(produces, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -77,7 +78,7 @@ public final class ProducesRequestCondition extends AbstractRequestCondition<Pro
|
||||
* @param produces expressions with syntax defined by {@link RequestMapping#produces()}
|
||||
* @param headers expressions with syntax defined by {@link RequestMapping#headers()}
|
||||
*/
|
||||
public ProducesRequestCondition(String[] produces, String[] headers) {
|
||||
public ProducesRequestCondition(String[] produces, @Nullable String[] headers) {
|
||||
this(produces, headers, null);
|
||||
}
|
||||
|
||||
@@ -88,7 +89,9 @@ public final class ProducesRequestCondition extends AbstractRequestCondition<Pro
|
||||
* @param headers expressions with syntax defined by {@link RequestMapping#headers()}
|
||||
* @param manager used to determine requested media types
|
||||
*/
|
||||
public ProducesRequestCondition(String[] produces, String[] headers, ContentNegotiationManager manager) {
|
||||
public ProducesRequestCondition(String[] produces, @Nullable String[] headers,
|
||||
@Nullable ContentNegotiationManager manager) {
|
||||
|
||||
this.expressions = new ArrayList<>(parseExpressions(produces, headers));
|
||||
Collections.sort(this.expressions);
|
||||
this.contentNegotiationManager = (manager != null ? manager : new ContentNegotiationManager());
|
||||
@@ -97,14 +100,16 @@ public final class ProducesRequestCondition extends AbstractRequestCondition<Pro
|
||||
/**
|
||||
* Private constructor with already parsed media type expressions.
|
||||
*/
|
||||
private ProducesRequestCondition(Collection<ProduceMediaTypeExpression> expressions, ContentNegotiationManager manager) {
|
||||
private ProducesRequestCondition(Collection<ProduceMediaTypeExpression> expressions,
|
||||
@Nullable ContentNegotiationManager manager) {
|
||||
|
||||
this.expressions = new ArrayList<>(expressions);
|
||||
Collections.sort(this.expressions);
|
||||
this.contentNegotiationManager = (manager != null ? manager : new ContentNegotiationManager());
|
||||
}
|
||||
|
||||
|
||||
private Set<ProduceMediaTypeExpression> parseExpressions(String[] produces, String[] headers) {
|
||||
private Set<ProduceMediaTypeExpression> parseExpressions(String[] produces, @Nullable String[] headers) {
|
||||
Set<ProduceMediaTypeExpression> result = new LinkedHashSet<>();
|
||||
if (headers != null) {
|
||||
for (String header : headers) {
|
||||
@@ -116,10 +121,8 @@ public final class ProducesRequestCondition extends AbstractRequestCondition<Pro
|
||||
}
|
||||
}
|
||||
}
|
||||
if (produces != null) {
|
||||
for (String produce : produces) {
|
||||
result.add(new ProduceMediaTypeExpression(produce));
|
||||
}
|
||||
for (String produce : produces) {
|
||||
result.add(new ProduceMediaTypeExpression(produce));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -20,13 +20,13 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.cors.CorsUtils;
|
||||
|
||||
@@ -43,7 +43,6 @@ public final class RequestMethodsRequestCondition extends AbstractRequestConditi
|
||||
private static final RequestMethodsRequestCondition GET_CONDITION =
|
||||
new RequestMethodsRequestCondition(RequestMethod.GET);
|
||||
|
||||
|
||||
private final Set<RequestMethod> methods;
|
||||
|
||||
|
||||
@@ -53,7 +52,7 @@ public final class RequestMethodsRequestCondition extends AbstractRequestConditi
|
||||
* if, 0 the condition will match to every request
|
||||
*/
|
||||
public RequestMethodsRequestCondition(RequestMethod... requestMethods) {
|
||||
this(asList(requestMethods));
|
||||
this(Arrays.asList(requestMethods));
|
||||
}
|
||||
|
||||
private RequestMethodsRequestCondition(Collection<RequestMethod> requestMethods) {
|
||||
@@ -61,11 +60,6 @@ public final class RequestMethodsRequestCondition extends AbstractRequestConditi
|
||||
}
|
||||
|
||||
|
||||
private static List<RequestMethod> asList(RequestMethod... requestMethods) {
|
||||
return (requestMethods != null ? Arrays.asList(requestMethods) : Collections.emptyList());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns all {@link RequestMethod}s contained in this condition.
|
||||
*/
|
||||
@@ -126,6 +120,7 @@ public final class RequestMethodsRequestCondition extends AbstractRequestConditi
|
||||
* Hence empty conditions is a match, otherwise try to match to the HTTP
|
||||
* method in the "Access-Control-Request-Method" header.
|
||||
*/
|
||||
@Nullable
|
||||
private RequestMethodsRequestCondition matchPreFlight(HttpServletRequest request) {
|
||||
if (getMethods().isEmpty()) {
|
||||
return this;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -17,7 +17,6 @@
|
||||
package org.springframework.web.servlet.mvc.method;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
@@ -407,17 +406,17 @@ public final class RequestMappingInfo implements RequestCondition<RequestMapping
|
||||
|
||||
private static class DefaultBuilder implements Builder {
|
||||
|
||||
private String[] paths;
|
||||
private String[] paths = new String[0];
|
||||
|
||||
private RequestMethod[] methods;
|
||||
private RequestMethod[] methods = new RequestMethod[0];
|
||||
|
||||
private String[] params;
|
||||
private String[] params = new String[0];
|
||||
|
||||
private String[] headers;
|
||||
private String[] headers = new String[0];
|
||||
|
||||
private String[] consumes;
|
||||
private String[] consumes = new String[0];
|
||||
|
||||
private String[] produces;
|
||||
private String[] produces = new String[0];
|
||||
|
||||
private String mappingName;
|
||||
|
||||
@@ -493,7 +492,7 @@ public final class RequestMappingInfo implements RequestCondition<RequestMapping
|
||||
this.options.getFileExtensions());
|
||||
|
||||
return new RequestMappingInfo(this.mappingName, patternsCondition,
|
||||
new RequestMethodsRequestCondition(methods),
|
||||
new RequestMethodsRequestCondition(this.methods),
|
||||
new ParamsRequestCondition(this.params),
|
||||
new HeadersRequestCondition(this.headers),
|
||||
new ConsumesRequestCondition(this.consumes, this.headers),
|
||||
@@ -536,7 +535,7 @@ public final class RequestMappingInfo implements RequestCondition<RequestMapping
|
||||
/**
|
||||
* Return a custom UrlPathHelper to use for the PatternsRequestCondition, if any.
|
||||
*/
|
||||
|
||||
@Nullable
|
||||
public UrlPathHelper getUrlPathHelper() {
|
||||
return this.urlPathHelper;
|
||||
}
|
||||
@@ -613,6 +612,7 @@ public final class RequestMappingInfo implements RequestCondition<RequestMapping
|
||||
* {@code registeredSuffixPatternMatch=true}, the extensions are obtained
|
||||
* from the configured {@code contentNegotiationManager}.
|
||||
*/
|
||||
@Nullable
|
||||
public List<String> getFileExtensions() {
|
||||
if (useRegisteredSuffixPatternMatch() && getContentNegotiationManager() != null) {
|
||||
return this.contentNegotiationManager.getAllFileExtensions();
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.springframework.http.converter.json.AbstractJackson2HttpMessageConver
|
||||
import org.springframework.http.converter.json.MappingJacksonValue;
|
||||
import org.springframework.http.server.ServerHttpRequest;
|
||||
import org.springframework.http.server.ServerHttpResponse;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* A convenient base class for {@code ResponseBodyAdvice} implementations
|
||||
@@ -41,10 +42,13 @@ public abstract class AbstractMappingJacksonResponseBodyAdvice implements Respon
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Object beforeBodyWrite(Object body, MethodParameter returnType,
|
||||
public final Object beforeBodyWrite(@Nullable Object body, MethodParameter returnType,
|
||||
MediaType contentType, Class<? extends HttpMessageConverter<?>> converterType,
|
||||
ServerHttpRequest request, ServerHttpResponse response) {
|
||||
|
||||
if (body == null) {
|
||||
return null;
|
||||
}
|
||||
MappingJacksonValue container = getOrCreateContainer(body);
|
||||
beforeBodyWriteInternal(container, contentType, returnType, request, response);
|
||||
return container;
|
||||
|
||||
@@ -29,7 +29,6 @@ import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -95,7 +94,7 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements
|
||||
* @since 4.2
|
||||
*/
|
||||
public AbstractMessageConverterMethodArgumentResolver(List<HttpMessageConverter<?>> converters,
|
||||
List<Object> requestResponseBodyAdvice) {
|
||||
@Nullable List<Object> requestResponseBodyAdvice) {
|
||||
|
||||
Assert.notEmpty(converters, "'messageConverters' must not be empty");
|
||||
this.messageConverters = converters;
|
||||
@@ -124,7 +123,7 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements
|
||||
* {@link RequestBodyAdvice} where each instance may be wrapped as a
|
||||
* {@link org.springframework.web.method.ControllerAdviceBean ControllerAdviceBean}.
|
||||
*/
|
||||
protected RequestResponseBodyAdviceChain getAdvice() {
|
||||
RequestResponseBodyAdviceChain getAdvice() {
|
||||
return this.advice;
|
||||
}
|
||||
|
||||
@@ -139,7 +138,8 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements
|
||||
* @throws IOException if the reading from the request fails
|
||||
* @throws HttpMediaTypeNotSupportedException if no suitable message converter is found
|
||||
*/
|
||||
protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, @Nullable MethodParameter parameter,
|
||||
@Nullable
|
||||
protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter,
|
||||
Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
|
||||
|
||||
HttpInputMessage inputMessage = createInputMessage(webRequest);
|
||||
@@ -151,7 +151,7 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements
|
||||
* from the given HttpInputMessage.
|
||||
* @param <T> the expected type of the argument value to be created
|
||||
* @param inputMessage the HTTP input message representing the current request
|
||||
* @param parameter the method parameter descriptor (may be {@code null})
|
||||
* @param parameter the method parameter descriptor
|
||||
* @param targetType the target type, not necessarily the same as the method
|
||||
* parameter type, e.g. for {@code HttpEntity<String>}.
|
||||
* @return the created method argument value
|
||||
@@ -160,7 +160,7 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Nullable
|
||||
protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, @Nullable MethodParameter parameter,
|
||||
protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter,
|
||||
Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
|
||||
|
||||
MediaType contentType;
|
||||
@@ -176,54 +176,40 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements
|
||||
contentType = MediaType.APPLICATION_OCTET_STREAM;
|
||||
}
|
||||
|
||||
Class<?> contextClass = (parameter != null ? parameter.getContainingClass() : null);
|
||||
Class<?> contextClass = parameter.getContainingClass();
|
||||
Class<T> targetClass = (targetType instanceof Class ? (Class<T>) targetType : null);
|
||||
if (targetClass == null) {
|
||||
ResolvableType resolvableType = (parameter != null ?
|
||||
ResolvableType.forMethodParameter(parameter) : ResolvableType.forType(targetType));
|
||||
ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter);
|
||||
targetClass = (Class<T>) resolvableType.resolve();
|
||||
}
|
||||
|
||||
HttpMethod httpMethod = ((HttpRequest) inputMessage).getMethod();
|
||||
HttpMethod httpMethod = (inputMessage instanceof HttpRequest ? ((HttpRequest) inputMessage).getMethod() : null);
|
||||
Object body = NO_VALUE;
|
||||
|
||||
EmptyBodyCheckingHttpInputMessage message;
|
||||
try {
|
||||
inputMessage = new EmptyBodyCheckingHttpInputMessage(inputMessage);
|
||||
message = new EmptyBodyCheckingHttpInputMessage(inputMessage);
|
||||
|
||||
for (HttpMessageConverter<?> converter : this.messageConverters) {
|
||||
Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();
|
||||
if (converter instanceof GenericHttpMessageConverter) {
|
||||
GenericHttpMessageConverter<?> genericConverter = (GenericHttpMessageConverter<?>) converter;
|
||||
if (genericConverter.canRead(targetType, contextClass, contentType)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Read [" + targetType + "] as \"" + contentType + "\" with [" + converter + "]");
|
||||
}
|
||||
if (inputMessage.getBody() != null) {
|
||||
inputMessage = getAdvice().beforeBodyRead(inputMessage, parameter, targetType, converterType);
|
||||
body = genericConverter.read(targetType, contextClass, inputMessage);
|
||||
body = getAdvice().afterBodyRead(body, inputMessage, parameter, targetType, converterType);
|
||||
}
|
||||
else {
|
||||
body = getAdvice().handleEmptyBody(null, inputMessage, parameter, targetType, converterType);
|
||||
}
|
||||
break;
|
||||
GenericHttpMessageConverter<?> genericConverter =
|
||||
(converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null);
|
||||
if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) :
|
||||
(targetClass != null && converter.canRead(targetClass, contentType))) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Read [" + targetType + "] as \"" + contentType + "\" with [" + converter + "]");
|
||||
}
|
||||
}
|
||||
else if (targetClass != null) {
|
||||
if (converter.canRead(targetClass, contentType)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Read [" + targetType + "] as \"" + contentType + "\" with [" + converter + "]");
|
||||
}
|
||||
if (inputMessage.getBody() != null) {
|
||||
inputMessage = getAdvice().beforeBodyRead(inputMessage, parameter, targetType, converterType);
|
||||
body = ((HttpMessageConverter<T>) converter).read(targetClass, inputMessage);
|
||||
body = getAdvice().afterBodyRead(body, inputMessage, parameter, targetType, converterType);
|
||||
}
|
||||
else {
|
||||
body = getAdvice().handleEmptyBody(null, inputMessage, parameter, targetType, converterType);
|
||||
}
|
||||
break;
|
||||
if (message.hasBody()) {
|
||||
HttpInputMessage inputMessageToUse =
|
||||
getAdvice().beforeBodyRead(message, parameter, targetType, converterType);
|
||||
body = (genericConverter != null ? genericConverter.read(targetType, contextClass, message) :
|
||||
((HttpMessageConverter<T>) converter).read(targetClass, message));
|
||||
body = getAdvice().afterBodyRead(body, inputMessageToUse, parameter, targetType, converterType);
|
||||
}
|
||||
else {
|
||||
body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -233,7 +219,7 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements
|
||||
|
||||
if (body == NO_VALUE) {
|
||||
if (httpMethod == null || !SUPPORTED_METHODS.contains(httpMethod) ||
|
||||
(noContentType && inputMessage.getBody() == null)) {
|
||||
(noContentType && !message.hasBody())) {
|
||||
return null;
|
||||
}
|
||||
throw new HttpMediaTypeNotSupportedException(contentType, this.allSupportedMediaTypes);
|
||||
@@ -249,6 +235,7 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements
|
||||
*/
|
||||
protected ServletServerHttpRequest createInputMessage(NativeWebRequest webRequest) {
|
||||
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
|
||||
Assert.state(servletRequest != null, "No HttpServletRequest");
|
||||
return new ServletServerHttpRequest(servletRequest);
|
||||
}
|
||||
|
||||
@@ -284,7 +271,7 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements
|
||||
*/
|
||||
protected boolean isBindExceptionRequired(WebDataBinder binder, MethodParameter parameter) {
|
||||
int i = parameter.getParameterIndex();
|
||||
Class<?>[] paramTypes = parameter.getMethod().getParameterTypes();
|
||||
Class<?>[] paramTypes = parameter.getExecutable().getParameterTypes();
|
||||
boolean hasBindingResult = (paramTypes.length > (i + 1) && Errors.class.isAssignableFrom(paramTypes[i + 1]));
|
||||
return !hasBindingResult;
|
||||
}
|
||||
@@ -296,7 +283,8 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements
|
||||
* @return the adapted argument, or the original resolved argument as-is
|
||||
* @since 4.3.5
|
||||
*/
|
||||
protected Object adaptArgumentIfNecessary(Object arg, MethodParameter parameter) {
|
||||
@Nullable
|
||||
protected Object adaptArgumentIfNecessary(@Nullable Object arg, MethodParameter parameter) {
|
||||
if (parameter.getParameterType() == Optional.class) {
|
||||
if (arg == null || (arg instanceof Collection && ((Collection) arg).isEmpty()) ||
|
||||
(arg instanceof Object[] && ((Object[]) arg).length == 0)) {
|
||||
@@ -316,16 +304,10 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements
|
||||
|
||||
private final InputStream body;
|
||||
|
||||
private final HttpMethod method;
|
||||
|
||||
|
||||
public EmptyBodyCheckingHttpInputMessage(HttpInputMessage inputMessage) throws IOException {
|
||||
this.headers = inputMessage.getHeaders();
|
||||
InputStream inputStream = inputMessage.getBody();
|
||||
if (inputStream == null) {
|
||||
this.body = null;
|
||||
}
|
||||
else if (inputStream.markSupported()) {
|
||||
if (inputStream.markSupported()) {
|
||||
inputStream.mark(1);
|
||||
this.body = (inputStream.read() != -1 ? inputStream : null);
|
||||
inputStream.reset();
|
||||
@@ -341,7 +323,6 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements
|
||||
pushbackInputStream.unread(b);
|
||||
}
|
||||
}
|
||||
this.method = ((HttpRequest) inputMessage).getMethod();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -350,12 +331,12 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getBody() throws IOException {
|
||||
public InputStream getBody() {
|
||||
return this.body;
|
||||
}
|
||||
|
||||
public HttpMethod getMethod() {
|
||||
return this.method;
|
||||
public boolean hasBody() {
|
||||
return (this.body != null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ import org.springframework.http.converter.HttpMessageNotWritableException;
|
||||
import org.springframework.http.server.ServletServerHttpRequest;
|
||||
import org.springframework.http.server.ServletServerHttpResponse;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.HttpMediaTypeNotAcceptableException;
|
||||
@@ -74,13 +75,14 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
|
||||
|
||||
private static final MediaType MEDIA_TYPE_APPLICATION = new MediaType("application");
|
||||
|
||||
private static final UrlPathHelper DECODING_URL_PATH_HELPER = new UrlPathHelper();
|
||||
|
||||
private static final UrlPathHelper RAW_URL_PATH_HELPER = new UrlPathHelper();
|
||||
private static final UrlPathHelper decodingUrlPathHelper = new UrlPathHelper();
|
||||
|
||||
private static final UrlPathHelper rawUrlPathHelper = new UrlPathHelper();
|
||||
|
||||
static {
|
||||
RAW_URL_PATH_HELPER.setRemoveSemicolonContent(false);
|
||||
RAW_URL_PATH_HELPER.setUrlDecode(false);
|
||||
rawUrlPathHelper.setRemoveSemicolonContent(false);
|
||||
rawUrlPathHelper.setUrlDecode(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -95,14 +97,14 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
|
||||
* Constructor with list of converters only.
|
||||
*/
|
||||
protected AbstractMessageConverterMethodProcessor(List<HttpMessageConverter<?>> converters) {
|
||||
this(converters, null);
|
||||
this(converters, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor with list of converters and ContentNegotiationManager.
|
||||
*/
|
||||
protected AbstractMessageConverterMethodProcessor(List<HttpMessageConverter<?>> converters,
|
||||
ContentNegotiationManager contentNegotiationManager) {
|
||||
@Nullable ContentNegotiationManager contentNegotiationManager) {
|
||||
|
||||
this(converters, contentNegotiationManager, null);
|
||||
}
|
||||
@@ -112,7 +114,7 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
|
||||
* as request/response body advice instances.
|
||||
*/
|
||||
protected AbstractMessageConverterMethodProcessor(List<HttpMessageConverter<?>> converters,
|
||||
ContentNegotiationManager manager, List<Object> requestResponseBodyAdvice) {
|
||||
@Nullable ContentNegotiationManager manager, @Nullable List<Object> requestResponseBodyAdvice) {
|
||||
|
||||
super(converters, requestResponseBodyAdvice);
|
||||
this.contentNegotiationManager = (manager != null ? manager : new ContentNegotiationManager());
|
||||
@@ -135,6 +137,7 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
|
||||
*/
|
||||
protected ServletServerHttpResponse createOutputMessage(NativeWebRequest webRequest) {
|
||||
HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
|
||||
Assert.state(response != null, "No HttpServletResponse");
|
||||
return new ServletServerHttpResponse(response);
|
||||
}
|
||||
|
||||
@@ -161,7 +164,7 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
|
||||
* by the {@code Accept} header on the request cannot be met by the message converters
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <T> void writeWithMessageConverters(T value, MethodParameter returnType,
|
||||
protected <T> void writeWithMessageConverters(@Nullable T value, MethodParameter returnType,
|
||||
ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
|
||||
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
|
||||
|
||||
@@ -185,7 +188,7 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
|
||||
List<MediaType> producibleMediaTypes = getProducibleMediaTypes(request, valueType, declaredType);
|
||||
|
||||
if (outputValue != null && producibleMediaTypes.isEmpty()) {
|
||||
throw new IllegalArgumentException("No converter found for return value of type: " + valueType);
|
||||
throw new HttpMessageNotWritableException("No converter found for return value of type: " + valueType);
|
||||
}
|
||||
|
||||
Set<MediaType> compatibleMediaTypes = new LinkedHashSet<>();
|
||||
@@ -267,7 +270,7 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
|
||||
* return type needs to be examined possibly including generic type determination
|
||||
* (e.g. {@code ResponseEntity<T>}).
|
||||
*/
|
||||
protected Class<?> getReturnValueType(Object value, MethodParameter returnType) {
|
||||
protected Class<?> getReturnValueType(@Nullable Object value, MethodParameter returnType) {
|
||||
return (value != null ? value.getClass() : returnType.getParameterType());
|
||||
}
|
||||
|
||||
@@ -275,9 +278,10 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
|
||||
* Return the generic type of the {@code returnType} (or of the nested type
|
||||
* if it is an {@link HttpEntity}).
|
||||
*/
|
||||
@Nullable
|
||||
private Type getGenericType(MethodParameter returnType) {
|
||||
if (HttpEntity.class.isAssignableFrom(returnType.getParameterType())) {
|
||||
return ResolvableType.forType(returnType.getGenericParameterType()).getGeneric(0).getType();
|
||||
return ResolvableType.forType(returnType.getGenericParameterType()).getGeneric().getType();
|
||||
}
|
||||
else {
|
||||
return returnType.getGenericParameterType();
|
||||
@@ -365,7 +369,7 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
|
||||
}
|
||||
|
||||
HttpServletRequest servletRequest = request.getServletRequest();
|
||||
String requestUri = RAW_URL_PATH_HELPER.getOriginatingRequestUri(servletRequest);
|
||||
String requestUri = rawUrlPathHelper.getOriginatingRequestUri(servletRequest);
|
||||
|
||||
int index = requestUri.lastIndexOf('/') + 1;
|
||||
String filename = requestUri.substring(index);
|
||||
@@ -377,10 +381,10 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
|
||||
filename = filename.substring(0, index);
|
||||
}
|
||||
|
||||
filename = DECODING_URL_PATH_HELPER.decodeRequestString(servletRequest, filename);
|
||||
filename = decodingUrlPathHelper.decodeRequestString(servletRequest, filename);
|
||||
String ext = StringUtils.getFilenameExtension(filename);
|
||||
|
||||
pathParams = DECODING_URL_PATH_HELPER.decodeRequestString(servletRequest, pathParams);
|
||||
pathParams = decodingUrlPathHelper.decodeRequestString(servletRequest, pathParams);
|
||||
String extInPathParams = StringUtils.getFilenameExtension(pathParams);
|
||||
|
||||
if (!safeExtension(servletRequest, ext) || !safeExtension(servletRequest, extInPathParams)) {
|
||||
@@ -389,7 +393,7 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private boolean safeExtension(HttpServletRequest request, String extension) {
|
||||
private boolean safeExtension(HttpServletRequest request, @Nullable String extension) {
|
||||
if (!StringUtils.hasText(extension)) {
|
||||
return true;
|
||||
}
|
||||
@@ -408,13 +412,13 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return safeMediaTypesForExtension(extension);
|
||||
return safeMediaTypesForExtension(new ServletWebRequest(request), extension);
|
||||
}
|
||||
|
||||
private boolean safeMediaTypesForExtension(String extension) {
|
||||
private boolean safeMediaTypesForExtension(NativeWebRequest request, String extension) {
|
||||
List<MediaType> mediaTypes = null;
|
||||
try {
|
||||
mediaTypes = this.pathStrategy.resolveMediaTypeKey(null, extension);
|
||||
mediaTypes = this.pathStrategy.resolveMediaTypeKey(request, extension);
|
||||
}
|
||||
catch (HttpMediaTypeNotAcceptableException ex) {
|
||||
// Ignore
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.web.servlet.mvc.method.annotation;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.context.request.async.WebAsyncTask;
|
||||
import org.springframework.web.context.request.async.WebAsyncUtils;
|
||||
@@ -46,7 +47,7 @@ public class AsyncTaskMethodReturnValueHandler implements HandlerMethodReturnVal
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleReturnValue(Object returnValue, MethodParameter returnType,
|
||||
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
|
||||
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
|
||||
|
||||
if (returnValue == null) {
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.springframework.web.servlet.mvc.method.annotation;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.context.request.async.WebAsyncUtils;
|
||||
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
|
||||
@@ -38,7 +39,7 @@ public class CallableMethodReturnValueHandler implements HandlerMethodReturnValu
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleReturnValue(Object returnValue, MethodParameter returnType,
|
||||
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
|
||||
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
|
||||
|
||||
if (returnValue == null) {
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.util.concurrent.CompletionStage;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.ListenableFutureCallback;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
@@ -47,7 +48,7 @@ public class DeferredResultMethodReturnValueHandler implements HandlerMethodRetu
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleReturnValue(Object returnValue, MethodParameter returnType,
|
||||
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
|
||||
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
|
||||
|
||||
if (returnValue == null) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -24,7 +24,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
@@ -132,7 +131,7 @@ public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExce
|
||||
* Configure the complete list of supported argument types thus overriding
|
||||
* the resolvers that would otherwise be configured by default.
|
||||
*/
|
||||
public void setArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
|
||||
public void setArgumentResolvers(@Nullable List<HandlerMethodArgumentResolver> argumentResolvers) {
|
||||
if (argumentResolvers == null) {
|
||||
this.argumentResolvers = null;
|
||||
}
|
||||
@@ -172,7 +171,7 @@ public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExce
|
||||
* Configure the complete list of supported return value types thus
|
||||
* overriding handlers that would otherwise be configured by default.
|
||||
*/
|
||||
public void setReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
|
||||
public void setReturnValueHandlers(@Nullable List<HandlerMethodReturnValueHandler> returnValueHandlers) {
|
||||
if (returnValueHandlers == null) {
|
||||
this.returnValueHandlers = null;
|
||||
}
|
||||
@@ -227,7 +226,7 @@ public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExce
|
||||
* but before the body is written to the response with the selected
|
||||
* {@code HttpMessageConverter}.
|
||||
*/
|
||||
public void setResponseBodyAdvice(List<ResponseBodyAdvice<?>> responseBodyAdvice) {
|
||||
public void setResponseBodyAdvice(@Nullable List<ResponseBodyAdvice<?>> responseBodyAdvice) {
|
||||
this.responseBodyAdvice.clear();
|
||||
if (responseBodyAdvice != null) {
|
||||
this.responseBodyAdvice.addAll(responseBodyAdvice);
|
||||
@@ -239,6 +238,7 @@ public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExce
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ApplicationContext getApplicationContext() {
|
||||
return this.applicationContext;
|
||||
}
|
||||
@@ -271,14 +271,18 @@ public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExce
|
||||
AnnotationAwareOrderComparator.sort(adviceBeans);
|
||||
|
||||
for (ControllerAdviceBean adviceBean : adviceBeans) {
|
||||
ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(adviceBean.getBeanType());
|
||||
Class<?> beanType = adviceBean.getBeanType();
|
||||
if (beanType == null) {
|
||||
throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean);
|
||||
}
|
||||
ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(beanType);
|
||||
if (resolver.hasExceptionMappings()) {
|
||||
this.exceptionHandlerAdviceCache.put(adviceBean, resolver);
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Detected @ExceptionHandler methods in " + adviceBean);
|
||||
}
|
||||
}
|
||||
if (ResponseBodyAdvice.class.isAssignableFrom(adviceBean.getBeanType())) {
|
||||
if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
|
||||
this.responseBodyAdvice.add(adviceBean);
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Detected ResponseBodyAdvice implementation in " + adviceBean);
|
||||
@@ -413,7 +417,6 @@ public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExce
|
||||
}
|
||||
if (model instanceof RedirectAttributes) {
|
||||
Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
|
||||
request = webRequest.getNativeRequest(HttpServletRequest.class);
|
||||
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
|
||||
}
|
||||
return mav;
|
||||
|
||||
@@ -52,7 +52,7 @@ public class ExtendedServletRequestDataBinder extends ServletRequestDataBinder {
|
||||
* @param objectName the name of the target object
|
||||
* @see #DEFAULT_OBJECT_NAME
|
||||
*/
|
||||
public ExtendedServletRequestDataBinder(@Nullable Object target, String objectName) {
|
||||
public ExtendedServletRequestDataBinder(@Nullable Object target, @Nullable String objectName) {
|
||||
super(target, objectName);
|
||||
}
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodPro
|
||||
* {@code ResponseEntity}.
|
||||
*/
|
||||
public HttpEntityMethodProcessor(List<HttpMessageConverter<?>> converters,
|
||||
ContentNegotiationManager manager, List<Object> requestResponseBodyAdvice) {
|
||||
@Nullable ContentNegotiationManager manager, List<Object> requestResponseBodyAdvice) {
|
||||
|
||||
super(converters, manager, requestResponseBodyAdvice);
|
||||
}
|
||||
@@ -122,8 +122,8 @@ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodPro
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, WebDataBinderFactory binderFactory)
|
||||
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory)
|
||||
throws IOException, HttpMediaTypeNotSupportedException {
|
||||
|
||||
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
|
||||
@@ -164,7 +164,7 @@ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodPro
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleReturnValue(Object returnValue, MethodParameter returnType,
|
||||
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
|
||||
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
|
||||
|
||||
mavContainer.setRequestHandled(true);
|
||||
@@ -221,24 +221,25 @@ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodPro
|
||||
}
|
||||
|
||||
private List<String> getVaryRequestHeadersToAdd(HttpHeaders responseHeaders, HttpHeaders entityHeaders) {
|
||||
if (!responseHeaders.containsKey(HttpHeaders.VARY)) {
|
||||
return entityHeaders.getVary();
|
||||
}
|
||||
List<String> entityHeadersVary = entityHeaders.getVary();
|
||||
List<String> result = new ArrayList<>(entityHeadersVary);
|
||||
for (String header : responseHeaders.get(HttpHeaders.VARY)) {
|
||||
for (String existing : StringUtils.tokenizeToStringArray(header, ",")) {
|
||||
if ("*".equals(existing)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
for (String value : entityHeadersVary) {
|
||||
if (value.equalsIgnoreCase(existing)) {
|
||||
result.remove(value);
|
||||
List<String> vary = responseHeaders.get(HttpHeaders.VARY);
|
||||
if (vary != null) {
|
||||
List<String> result = new ArrayList<>(entityHeadersVary);
|
||||
for (String header : vary) {
|
||||
for (String existing : StringUtils.tokenizeToStringArray(header, ",")) {
|
||||
if ("*".equals(existing)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
for (String value : entityHeadersVary) {
|
||||
if (value.equalsIgnoreCase(existing)) {
|
||||
result.remove(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
return entityHeadersVary;
|
||||
}
|
||||
|
||||
private boolean isResourceNotModified(ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage) {
|
||||
@@ -262,15 +263,19 @@ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodPro
|
||||
Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
|
||||
if (!CollectionUtils.isEmpty(flashAttributes)) {
|
||||
HttpServletRequest req = request.getNativeRequest(HttpServletRequest.class);
|
||||
HttpServletResponse res = request.getNativeRequest(HttpServletResponse.class);
|
||||
RequestContextUtils.getOutputFlashMap(req).putAll(flashAttributes);
|
||||
RequestContextUtils.saveOutputFlashMap(location, req, res);
|
||||
HttpServletResponse res = request.getNativeResponse(HttpServletResponse.class);
|
||||
if (req != null) {
|
||||
RequestContextUtils.getOutputFlashMap(req).putAll(flashAttributes);
|
||||
if (res != null) {
|
||||
RequestContextUtils.saveOutputFlashMap(location, req, res);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> getReturnValueType(Object returnValue, MethodParameter returnType) {
|
||||
protected Class<?> getReturnValueType(@Nullable Object returnValue, MethodParameter returnType) {
|
||||
if (returnValue != null) {
|
||||
return returnValue.getClass();
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.server.ServletServerHttpResponse;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
|
||||
@@ -41,16 +42,17 @@ public class HttpHeadersReturnValueHandler implements HandlerMethodReturnValueHa
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("resource")
|
||||
public void handleReturnValue(Object returnValue, MethodParameter returnType,
|
||||
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
|
||||
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
|
||||
|
||||
mavContainer.setRequestHandled(true);
|
||||
|
||||
Assert.isInstanceOf(HttpHeaders.class, returnValue, "HttpHeaders expected");
|
||||
Assert.state(returnValue instanceof HttpHeaders, "HttpHeaders expected");
|
||||
HttpHeaders headers = (HttpHeaders) returnValue;
|
||||
|
||||
if (!headers.isEmpty()) {
|
||||
HttpServletResponse servletResponse = webRequest.getNativeResponse(HttpServletResponse.class);
|
||||
Assert.state(servletResponse != null, "No HttpServletResponse");
|
||||
ServletServerHttpResponse outputMessage = new ServletServerHttpResponse(servletResponse);
|
||||
outputMessage.getHeaders().putAll(headers);
|
||||
outputMessage.getBody(); // flush headers
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -26,6 +26,7 @@ import org.springframework.http.HttpInputMessage;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJacksonInputMessage;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link RequestBodyAdvice} implementation that adds support for Jackson's
|
||||
@@ -40,8 +41,6 @@ import org.springframework.http.converter.json.MappingJacksonInputMessage;
|
||||
* be specified, the use for a request body advice is only supported with
|
||||
* exactly one class argument. Consider the use of a composite interface.
|
||||
*
|
||||
* <p>Jackson 2.5 or later is required for parameter-level use of {@code @JsonView}.
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 4.2
|
||||
* @see com.fasterxml.jackson.annotation.JsonView
|
||||
@@ -61,12 +60,15 @@ public class JsonViewRequestBodyAdvice extends RequestBodyAdviceAdapter {
|
||||
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter methodParameter,
|
||||
Type targetType, Class<? extends HttpMessageConverter<?>> selectedConverterType) throws IOException {
|
||||
|
||||
JsonView annotation = methodParameter.getParameterAnnotation(JsonView.class);
|
||||
Class<?>[] classes = annotation.value();
|
||||
JsonView ann = methodParameter.getParameterAnnotation(JsonView.class);
|
||||
Assert.state(ann != null, "No JsonView annotation");
|
||||
|
||||
Class<?>[] classes = ann.value();
|
||||
if (classes.length != 1) {
|
||||
throw new IllegalArgumentException(
|
||||
"@JsonView only supported for request body advice with exactly 1 class argument: " + methodParameter);
|
||||
}
|
||||
|
||||
return new MappingJacksonInputMessage(inputMessage.getBody(), inputMessage.getHeaders(), classes[0]);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -24,6 +24,7 @@ import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJacksonValue;
|
||||
import org.springframework.http.server.ServerHttpRequest;
|
||||
import org.springframework.http.server.ServerHttpResponse;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link ResponseBodyAdvice} implementation that adds support for Jackson's
|
||||
@@ -54,12 +55,15 @@ public class JsonViewResponseBodyAdvice extends AbstractMappingJacksonResponseBo
|
||||
protected void beforeBodyWriteInternal(MappingJacksonValue bodyContainer, MediaType contentType,
|
||||
MethodParameter returnType, ServerHttpRequest request, ServerHttpResponse response) {
|
||||
|
||||
JsonView annotation = returnType.getMethodAnnotation(JsonView.class);
|
||||
Class<?>[] classes = annotation.value();
|
||||
JsonView ann = returnType.getMethodAnnotation(JsonView.class);
|
||||
Assert.state(ann != null, "No JsonView annotation");
|
||||
|
||||
Class<?>[] classes = ann.value();
|
||||
if (classes.length != 1) {
|
||||
throw new IllegalArgumentException(
|
||||
"@JsonView only supported for response body advice with exactly 1 class argument: " + returnType);
|
||||
}
|
||||
|
||||
bodyContainer.setSerializationView(classes[0]);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -22,6 +22,8 @@ import java.util.Map;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
@@ -58,8 +60,8 @@ public class MatrixVariableMapMethodArgumentResolver implements HandlerMethodArg
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest request, WebDataBinderFactory binderFactory) throws Exception {
|
||||
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest request, @Nullable WebDataBinderFactory binderFactory) throws Exception {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, MultiValueMap<String, String>> matrixVariables =
|
||||
@@ -71,7 +73,9 @@ public class MatrixVariableMapMethodArgumentResolver implements HandlerMethodArg
|
||||
}
|
||||
|
||||
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
|
||||
String pathVariable = parameter.getParameterAnnotation(MatrixVariable.class).pathVar();
|
||||
MatrixVariable ann = parameter.getParameterAnnotation(MatrixVariable.class);
|
||||
Assert.state(ann != null, "No MatrixVariable annotation");
|
||||
String pathVariable = ann.pathVar();
|
||||
|
||||
if (!pathVariable.equals(ValueConstants.DEFAULT_NONE)) {
|
||||
MultiValueMap<String, String> mapForPathVariable = matrixVariables.get(pathVariable);
|
||||
@@ -97,7 +101,8 @@ public class MatrixVariableMapMethodArgumentResolver implements HandlerMethodArg
|
||||
if (!MultiValueMap.class.isAssignableFrom(parameter.getParameterType())) {
|
||||
ResolvableType[] genericTypes = ResolvableType.forMethodParameter(parameter).getGenerics();
|
||||
if (genericTypes.length == 2) {
|
||||
return !List.class.isAssignableFrom(genericTypes[1].getRawClass());
|
||||
Class<?> declaredClass = genericTypes[1].getRawClass();
|
||||
return (declaredClass == null || !List.class.isAssignableFrom(declaredClass));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -21,6 +21,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -55,16 +56,17 @@ public class MatrixVariableMethodArgumentResolver extends AbstractNamedValueMeth
|
||||
return false;
|
||||
}
|
||||
if (Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) {
|
||||
String variableName = parameter.getParameterAnnotation(MatrixVariable.class).name();
|
||||
return StringUtils.hasText(variableName);
|
||||
MatrixVariable matrixVariable = parameter.getParameterAnnotation(MatrixVariable.class);
|
||||
return (matrixVariable != null && StringUtils.hasText(matrixVariable.name()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
|
||||
MatrixVariable annotation = parameter.getParameterAnnotation(MatrixVariable.class);
|
||||
return new MatrixVariableNamedValueInfo(annotation);
|
||||
MatrixVariable ann = parameter.getParameterAnnotation(MatrixVariable.class);
|
||||
Assert.state(ann != null, "No MatrixVariable annotation");
|
||||
return new MatrixVariableNamedValueInfo(ann);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -76,7 +78,9 @@ public class MatrixVariableMethodArgumentResolver extends AbstractNamedValueMeth
|
||||
return null;
|
||||
}
|
||||
|
||||
String pathVar = parameter.getParameterAnnotation(MatrixVariable.class).pathVar();
|
||||
MatrixVariable ann = parameter.getParameterAnnotation(MatrixVariable.class);
|
||||
Assert.state(ann != null, "No MatrixVariable annotation");
|
||||
String pathVar = ann.pathVar();
|
||||
List<String> paramValues = null;
|
||||
|
||||
if (!pathVar.equals(ValueConstants.DEFAULT_NONE)) {
|
||||
|
||||
@@ -75,7 +75,7 @@ public class ModelAndViewMethodReturnValueHandler implements HandlerMethodReturn
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleReturnValue(Object returnValue, MethodParameter returnType,
|
||||
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
|
||||
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
|
||||
|
||||
if (returnValue == null) {
|
||||
|
||||
@@ -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.
|
||||
@@ -20,7 +20,9 @@ import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.ui.ExtendedModelMap;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.method.annotation.ModelAttributeMethodProcessor;
|
||||
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
|
||||
@@ -61,7 +63,7 @@ public class ModelAndViewResolverMethodReturnValueHandler implements HandlerMeth
|
||||
/**
|
||||
* Create a new instance.
|
||||
*/
|
||||
public ModelAndViewResolverMethodReturnValueHandler(List<ModelAndViewResolver> mavResolvers) {
|
||||
public ModelAndViewResolverMethodReturnValueHandler(@Nullable List<ModelAndViewResolver> mavResolvers) {
|
||||
this.mavResolvers = mavResolvers;
|
||||
}
|
||||
|
||||
@@ -75,13 +77,14 @@ public class ModelAndViewResolverMethodReturnValueHandler implements HandlerMeth
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleReturnValue(Object returnValue, MethodParameter returnType,
|
||||
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
|
||||
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
|
||||
|
||||
if (this.mavResolvers != null) {
|
||||
for (ModelAndViewResolver mavResolver : this.mavResolvers) {
|
||||
Class<?> handlerType = returnType.getContainingClass();
|
||||
Method method = returnType.getMethod();
|
||||
Assert.state(method != null, "No handler method");
|
||||
ExtendedModelMap model = (ExtendedModelMap) mavContainer.getModel();
|
||||
ModelAndView mav = mavResolver.resolveModelAndView(method, handlerType, returnValue, model, webRequest);
|
||||
if (mav != ModelAndViewResolver.UNRESOLVED) {
|
||||
|
||||
@@ -22,7 +22,6 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
@@ -411,7 +410,7 @@ public class MvcUriComponentsBuilder {
|
||||
* @since 4.2
|
||||
*/
|
||||
public static UriComponentsBuilder fromMethod(UriComponentsBuilder baseUrl,
|
||||
Class<?> controllerType, Method method, Object... args) {
|
||||
@Nullable Class<?> controllerType, Method method, Object... args) {
|
||||
|
||||
return fromMethodInternal(baseUrl,
|
||||
(controllerType != null ? controllerType : method.getDeclaringClass()), method, args);
|
||||
@@ -429,7 +428,7 @@ public class MvcUriComponentsBuilder {
|
||||
return UriComponentsBuilder.newInstance().uriComponents(uriComponents);
|
||||
}
|
||||
|
||||
private static UriComponentsBuilder getBaseUrlToUse(UriComponentsBuilder baseUrl) {
|
||||
private static UriComponentsBuilder getBaseUrlToUse(@Nullable UriComponentsBuilder baseUrl) {
|
||||
if (baseUrl != null) {
|
||||
return baseUrl.cloneBuilder();
|
||||
}
|
||||
@@ -741,14 +740,15 @@ public class MvcUriComponentsBuilder {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Object intercept(Object obj, Method method, Object[] args, @Nullable MethodProxy proxy) {
|
||||
if (getControllerMethod.equals(method)) {
|
||||
if (method.equals(getControllerMethod)) {
|
||||
return this.controllerMethod;
|
||||
}
|
||||
else if (getArgumentValues.equals(method)) {
|
||||
else if (method.equals(getArgumentValues)) {
|
||||
return this.argumentValues;
|
||||
}
|
||||
else if (getControllerType.equals(method)) {
|
||||
else if (method.equals(getControllerType)) {
|
||||
return this.controllerType;
|
||||
}
|
||||
else if (ReflectionUtils.isObjectMethod(method)) {
|
||||
@@ -799,7 +799,7 @@ public class MvcUriComponentsBuilder {
|
||||
/**
|
||||
* @since 4.2
|
||||
*/
|
||||
public MethodArgumentBuilder(UriComponentsBuilder baseUrl, Class<?> controllerType, Method method) {
|
||||
public MethodArgumentBuilder(@Nullable UriComponentsBuilder baseUrl, Class<?> controllerType, Method method) {
|
||||
Assert.notNull(controllerType, "'controllerType' is required");
|
||||
Assert.notNull(method, "'method' is required");
|
||||
this.baseUrl = (baseUrl != null ? baseUrl : initBaseUrl());
|
||||
@@ -813,7 +813,8 @@ public class MvcUriComponentsBuilder {
|
||||
|
||||
private static UriComponentsBuilder initBaseUrl() {
|
||||
UriComponentsBuilder builder = ServletUriComponentsBuilder.fromCurrentServletMapping();
|
||||
return UriComponentsBuilder.fromPath(builder.build().getPath());
|
||||
String path = builder.build().getPath();
|
||||
return (path != null ? UriComponentsBuilder.fromPath(path) : UriComponentsBuilder.newInstance());
|
||||
}
|
||||
|
||||
public MethodArgumentBuilder arg(int index, Object value) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -21,6 +21,7 @@ import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
@@ -45,16 +46,16 @@ public class PathVariableMapMethodArgumentResolver implements HandlerMethodArgum
|
||||
@Override
|
||||
public boolean supportsParameter(MethodParameter parameter) {
|
||||
PathVariable ann = parameter.getParameterAnnotation(PathVariable.class);
|
||||
return (ann != null && (Map.class.isAssignableFrom(parameter.getParameterType()))
|
||||
&& !StringUtils.hasText(ann.value()));
|
||||
return (ann != null && Map.class.isAssignableFrom(parameter.getParameterType()) &&
|
||||
!StringUtils.hasText(ann.value()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Map with all URI template variables or an empty map.
|
||||
*/
|
||||
@Override
|
||||
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
|
||||
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, String> uriTemplateVars =
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -25,6 +25,7 @@ import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.MissingPathVariableException;
|
||||
import org.springframework.web.bind.ServletRequestBindingException;
|
||||
@@ -73,16 +74,17 @@ public class PathVariableMethodArgumentResolver extends AbstractNamedValueMethod
|
||||
return false;
|
||||
}
|
||||
if (Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType())) {
|
||||
String paramName = parameter.getParameterAnnotation(PathVariable.class).value();
|
||||
return StringUtils.hasText(paramName);
|
||||
PathVariable pathVariable = parameter.getParameterAnnotation(PathVariable.class);
|
||||
return (pathVariable != null && StringUtils.hasText(pathVariable.value()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
|
||||
PathVariable annotation = parameter.getParameterAnnotation(PathVariable.class);
|
||||
return new PathVariableNamedValueInfo(annotation);
|
||||
PathVariable ann = parameter.getParameterAnnotation(PathVariable.class);
|
||||
Assert.state(ann != null, "No PathVariable annotation");
|
||||
return new PathVariableNamedValueInfo(ann);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -100,7 +102,7 @@ public class PathVariableMethodArgumentResolver extends AbstractNamedValueMethod
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void handleResolvedValue(Object arg, String name, MethodParameter parameter,
|
||||
protected void handleResolvedValue(@Nullable Object arg, String name, MethodParameter parameter,
|
||||
@Nullable ModelAndViewContainer mavContainer, NativeWebRequest request) {
|
||||
|
||||
String key = View.PATH_VARIABLES;
|
||||
@@ -123,15 +125,13 @@ public class PathVariableMethodArgumentResolver extends AbstractNamedValueMethod
|
||||
|
||||
PathVariable ann = parameter.getParameterAnnotation(PathVariable.class);
|
||||
String name = (ann != null && !StringUtils.isEmpty(ann.value()) ? ann.value() : parameter.getParameterName());
|
||||
value = formatUriValue(conversionService, new TypeDescriptor(parameter.nestedIfOptional()), value);
|
||||
uriVariables.put(name, value);
|
||||
String formatted = formatUriValue(conversionService, new TypeDescriptor(parameter.nestedIfOptional()), value);
|
||||
uriVariables.put(name, formatted);
|
||||
}
|
||||
|
||||
protected String formatUriValue(ConversionService cs, TypeDescriptor sourceType, Object value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
else if (value instanceof String) {
|
||||
@Nullable
|
||||
protected String formatUriValue(@Nullable ConversionService cs, @Nullable TypeDescriptor sourceType, Object value) {
|
||||
if (value instanceof String) {
|
||||
return (String) value;
|
||||
}
|
||||
else if (cs != null) {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.web.servlet.mvc.method.annotation;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -335,19 +336,27 @@ class ReactiveTypeHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private SseEmitter.SseEventBuilder adapt(ServerSentEvent<?> event) {
|
||||
private SseEmitter.SseEventBuilder adapt(ServerSentEvent<?> sse) {
|
||||
SseEmitter.SseEventBuilder builder = SseEmitter.event();
|
||||
if (event.id() != null) {
|
||||
builder.id(event.id());
|
||||
String id = sse.id();
|
||||
String event = sse.event();
|
||||
Duration retry = sse.retry();
|
||||
String comment = sse.comment();
|
||||
Object data = sse.data();
|
||||
if (id != null) {
|
||||
builder.id(id);
|
||||
}
|
||||
if (event.comment() != null) {
|
||||
builder.comment(event.comment());
|
||||
if (event != null) {
|
||||
builder.name(event);
|
||||
}
|
||||
if (event.data() != null) {
|
||||
builder.data(event.data());
|
||||
if (data != null) {
|
||||
builder.data(data);
|
||||
}
|
||||
if (event.retry() != null) {
|
||||
builder.reconnectTime(event.retry().toMillis());
|
||||
if (retry != null) {
|
||||
builder.reconnectTime(retry.toMillis());
|
||||
}
|
||||
if (comment != null) {
|
||||
builder.comment(comment);
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -19,8 +19,10 @@ package org.springframework.web.servlet.mvc.method.annotation;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.validation.DataBinder;
|
||||
import org.springframework.web.bind.support.WebDataBinderFactory;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
@@ -50,11 +52,13 @@ public class RedirectAttributesMethodArgumentResolver implements HandlerMethodAr
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
|
||||
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
|
||||
|
||||
Assert.state(mavContainer != null, "RedirectAttributes argument only supported on regular handler methods");
|
||||
|
||||
ModelMap redirectAttributes;
|
||||
if(binderFactory != null) {
|
||||
if (binderFactory != null) {
|
||||
DataBinder dataBinder = binderFactory.createBinder(webRequest, null, null);
|
||||
redirectAttributes = new RedirectAttributesModelMap(dataBinder);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -19,6 +19,7 @@ package org.springframework.web.servlet.mvc.method.annotation;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.ServletRequestBindingException;
|
||||
import org.springframework.web.bind.annotation.RequestAttribute;
|
||||
import org.springframework.web.bind.annotation.ValueConstants;
|
||||
@@ -42,6 +43,7 @@ public class RequestAttributeMethodArgumentResolver extends AbstractNamedValueMe
|
||||
@Override
|
||||
protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
|
||||
RequestAttribute ann = parameter.getParameterAnnotation(RequestAttribute.class);
|
||||
Assert.state(ann != null, "No RequestAttribute annotation");
|
||||
return new NamedValueInfo(ann.name(), ann.required(), ValueConstants.DEFAULT_NONE);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -50,21 +50,6 @@ public interface RequestBodyAdvice {
|
||||
boolean supports(MethodParameter methodParameter, Type targetType,
|
||||
Class<? extends HttpMessageConverter<?>> converterType);
|
||||
|
||||
/**
|
||||
* Invoked second (and last) if the body is empty.
|
||||
* @param body set to {@code null} before the first advice is called
|
||||
* @param inputMessage the request
|
||||
* @param parameter the method parameter
|
||||
* @param targetType the target type, not necessarily the same as the method
|
||||
* parameter type, e.g. for {@code HttpEntity<String>}.
|
||||
* @param converterType the selected converter type
|
||||
* @return the value to use or {@code null} which may then raise an
|
||||
* {@code HttpMessageNotReadableException} if the argument is required.
|
||||
*/
|
||||
@Nullable
|
||||
Object handleEmptyBody(@Nullable Object body, HttpInputMessage inputMessage, MethodParameter parameter,
|
||||
Type targetType, Class<? extends HttpMessageConverter<?>> converterType);
|
||||
|
||||
/**
|
||||
* Invoked second before the request body is read and converted.
|
||||
* @param inputMessage the request
|
||||
@@ -79,7 +64,7 @@ public interface RequestBodyAdvice {
|
||||
|
||||
/**
|
||||
* Invoked third (and last) after the request body is converted to an Object.
|
||||
* @param body set to the converter Object before the 1st advice is called
|
||||
* @param body set to the converter Object before the first advice is called
|
||||
* @param inputMessage the request
|
||||
* @param parameter the target method parameter
|
||||
* @param targetType the target type, not necessarily the same as the method
|
||||
@@ -90,4 +75,20 @@ public interface RequestBodyAdvice {
|
||||
Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter,
|
||||
Type targetType, Class<? extends HttpMessageConverter<?>> converterType);
|
||||
|
||||
/**
|
||||
* Invoked second (and last) if the body is empty.
|
||||
* @param body usually set to {@code null} before the first advice is called
|
||||
* @param inputMessage the request
|
||||
* @param parameter the method parameter
|
||||
* @param targetType the target type, not necessarily the same as the method
|
||||
* parameter type, e.g. for {@code HttpEntity<String>}.
|
||||
* @param converterType the selected converter type
|
||||
* @return the value to use or {@code null} which may then raise an
|
||||
* {@code HttpMessageNotReadableException} if the argument is required.
|
||||
*/
|
||||
@Nullable
|
||||
Object handleEmptyBody(@Nullable Object body, HttpInputMessage inputMessage, MethodParameter parameter,
|
||||
Type targetType, Class<? extends HttpMessageConverter<?>> converterType);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -36,18 +36,6 @@ import org.springframework.lang.Nullable;
|
||||
*/
|
||||
public abstract class RequestBodyAdviceAdapter implements RequestBodyAdvice {
|
||||
|
||||
/**
|
||||
* The default implementation returns the body that was passed in.
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public Object handleEmptyBody(@Nullable Object body, HttpInputMessage inputMessage,
|
||||
MethodParameter parameter, Type targetType,
|
||||
Class<? extends HttpMessageConverter<?>> converterType) {
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
/**
|
||||
* The default implementation returns the InputMessage that was passed in.
|
||||
*/
|
||||
@@ -69,4 +57,16 @@ public abstract class RequestBodyAdviceAdapter implements RequestBodyAdvice {
|
||||
return body;
|
||||
}
|
||||
|
||||
/**
|
||||
* The default implementation returns the body that was passed in.
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public Object handleEmptyBody(@Nullable Object body, HttpInputMessage inputMessage,
|
||||
MethodParameter parameter, Type targetType,
|
||||
Class<? extends HttpMessageConverter<?>> converterType) {
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
@@ -208,7 +207,7 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
|
||||
* Configure the complete list of supported argument types thus overriding
|
||||
* the resolvers that would otherwise be configured by default.
|
||||
*/
|
||||
public void setArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
|
||||
public void setArgumentResolvers(@Nullable List<HandlerMethodArgumentResolver> argumentResolvers) {
|
||||
if (argumentResolvers == null) {
|
||||
this.argumentResolvers = null;
|
||||
}
|
||||
@@ -224,13 +223,13 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
|
||||
*/
|
||||
@Nullable
|
||||
public List<HandlerMethodArgumentResolver> getArgumentResolvers() {
|
||||
return (this.argumentResolvers != null) ? this.argumentResolvers.getResolvers() : null;
|
||||
return (this.argumentResolvers != null ? this.argumentResolvers.getResolvers() : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the supported argument types in {@code @InitBinder} methods.
|
||||
*/
|
||||
public void setInitBinderArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
|
||||
public void setInitBinderArgumentResolvers(@Nullable List<HandlerMethodArgumentResolver> argumentResolvers) {
|
||||
if (argumentResolvers == null) {
|
||||
this.initBinderArgumentResolvers = null;
|
||||
}
|
||||
@@ -270,7 +269,7 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
|
||||
* Configure the complete list of supported return value types thus
|
||||
* overriding handlers that would otherwise be configured by default.
|
||||
*/
|
||||
public void setReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
|
||||
public void setReturnValueHandlers(@Nullable List<HandlerMethodReturnValueHandler> returnValueHandlers) {
|
||||
if (returnValueHandlers == null) {
|
||||
this.returnValueHandlers = null;
|
||||
}
|
||||
@@ -344,7 +343,7 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
|
||||
* request before it is read and converted for {@code @RequestBody} and
|
||||
* {@code HttpEntity} method arguments.
|
||||
*/
|
||||
public void setRequestBodyAdvice(List<RequestBodyAdvice> requestBodyAdvice) {
|
||||
public void setRequestBodyAdvice(@Nullable List<RequestBodyAdvice> requestBodyAdvice) {
|
||||
if (requestBodyAdvice != null) {
|
||||
this.requestResponseBodyAdvice.addAll(requestBodyAdvice);
|
||||
}
|
||||
@@ -355,7 +354,7 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
|
||||
* response before {@code @ResponseBody} or {@code ResponseEntity} return
|
||||
* values are written to the response body.
|
||||
*/
|
||||
public void setResponseBodyAdvice(List<ResponseBodyAdvice<?>> responseBodyAdvice) {
|
||||
public void setResponseBodyAdvice(@Nullable List<ResponseBodyAdvice<?>> responseBodyAdvice) {
|
||||
if (responseBodyAdvice != null) {
|
||||
this.requestResponseBodyAdvice.addAll(responseBodyAdvice);
|
||||
}
|
||||
@@ -562,36 +561,40 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
|
||||
logger.info("Looking for @ControllerAdvice: " + getApplicationContext());
|
||||
}
|
||||
|
||||
List<ControllerAdviceBean> beans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
|
||||
AnnotationAwareOrderComparator.sort(beans);
|
||||
List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
|
||||
AnnotationAwareOrderComparator.sort(adviceBeans);
|
||||
|
||||
List<Object> requestResponseBodyAdviceBeans = new ArrayList<>();
|
||||
|
||||
for (ControllerAdviceBean bean : beans) {
|
||||
Set<Method> attrMethods = MethodIntrospector.selectMethods(bean.getBeanType(), MODEL_ATTRIBUTE_METHODS);
|
||||
for (ControllerAdviceBean adviceBean : adviceBeans) {
|
||||
Class<?> beanType = adviceBean.getBeanType();
|
||||
if (beanType == null) {
|
||||
throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean);
|
||||
}
|
||||
Set<Method> attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS);
|
||||
if (!attrMethods.isEmpty()) {
|
||||
this.modelAttributeAdviceCache.put(bean, attrMethods);
|
||||
this.modelAttributeAdviceCache.put(adviceBean, attrMethods);
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Detected @ModelAttribute methods in " + bean);
|
||||
logger.info("Detected @ModelAttribute methods in " + adviceBean);
|
||||
}
|
||||
}
|
||||
Set<Method> binderMethods = MethodIntrospector.selectMethods(bean.getBeanType(), INIT_BINDER_METHODS);
|
||||
Set<Method> binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS);
|
||||
if (!binderMethods.isEmpty()) {
|
||||
this.initBinderAdviceCache.put(bean, binderMethods);
|
||||
this.initBinderAdviceCache.put(adviceBean, binderMethods);
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Detected @InitBinder methods in " + bean);
|
||||
logger.info("Detected @InitBinder methods in " + adviceBean);
|
||||
}
|
||||
}
|
||||
if (RequestBodyAdvice.class.isAssignableFrom(bean.getBeanType())) {
|
||||
requestResponseBodyAdviceBeans.add(bean);
|
||||
if (RequestBodyAdvice.class.isAssignableFrom(beanType)) {
|
||||
requestResponseBodyAdviceBeans.add(adviceBean);
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Detected RequestBodyAdvice bean in " + bean);
|
||||
logger.info("Detected RequestBodyAdvice bean in " + adviceBean);
|
||||
}
|
||||
}
|
||||
if (ResponseBodyAdvice.class.isAssignableFrom(bean.getBeanType())) {
|
||||
requestResponseBodyAdviceBeans.add(bean);
|
||||
if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
|
||||
requestResponseBodyAdviceBeans.add(adviceBean);
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Detected ResponseBodyAdvice bean in " + bean);
|
||||
logger.info("Detected ResponseBodyAdvice bean in " + adviceBean);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -971,7 +974,9 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
|
||||
if (model instanceof RedirectAttributes) {
|
||||
Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
|
||||
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
|
||||
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
|
||||
if (request != null) {
|
||||
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
|
||||
}
|
||||
}
|
||||
return mav;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -20,7 +20,6 @@ import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.context.EmbeddedValueResolverAware;
|
||||
@@ -161,6 +160,7 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
|
||||
/**
|
||||
* Return the file extensions to use for suffix pattern matching.
|
||||
*/
|
||||
@Nullable
|
||||
public List<String> getFileExtensions() {
|
||||
return this.config.getFileExtensions();
|
||||
}
|
||||
@@ -250,19 +250,20 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
|
||||
* result of merging annotation attributes within an annotation hierarchy.
|
||||
*/
|
||||
protected RequestMappingInfo createRequestMappingInfo(
|
||||
RequestMapping requestMapping, RequestCondition<?> customCondition) {
|
||||
RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) {
|
||||
|
||||
return RequestMappingInfo
|
||||
RequestMappingInfo.Builder builder = RequestMappingInfo
|
||||
.paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
|
||||
.methods(requestMapping.method())
|
||||
.params(requestMapping.params())
|
||||
.headers(requestMapping.headers())
|
||||
.consumes(requestMapping.consumes())
|
||||
.produces(requestMapping.produces())
|
||||
.mappingName(requestMapping.name())
|
||||
.customCondition(customCondition)
|
||||
.options(this.config)
|
||||
.build();
|
||||
.mappingName(requestMapping.name());
|
||||
if (customCondition != null) {
|
||||
builder.customCondition(customCondition);
|
||||
}
|
||||
return builder.options(this.config).build();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -317,7 +318,7 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
|
||||
return config.applyPermitDefaultValues();
|
||||
}
|
||||
|
||||
private void updateCorsConfig(CorsConfiguration config, CrossOrigin annotation) {
|
||||
private void updateCorsConfig(CorsConfiguration config, @Nullable CrossOrigin annotation) {
|
||||
if (annotation == null) {
|
||||
return;
|
||||
}
|
||||
@@ -352,7 +353,13 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
|
||||
}
|
||||
|
||||
private String resolveCorsAnnotationValue(String value) {
|
||||
return (this.embeddedValueResolver != null ? this.embeddedValueResolver.resolveStringValue(value) : value);
|
||||
if (this.embeddedValueResolver != null) {
|
||||
String resolved = this.embeddedValueResolver.resolveStringValue(value);
|
||||
return (resolved != null ? resolved : "");
|
||||
}
|
||||
else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.http.HttpInputMessage;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
@@ -106,10 +108,12 @@ public class RequestPartMethodArgumentResolver extends AbstractMessageConverterM
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest request, WebDataBinderFactory binderFactory) throws Exception {
|
||||
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest request, @Nullable WebDataBinderFactory binderFactory) throws Exception {
|
||||
|
||||
HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);
|
||||
Assert.state(servletRequest != null, "No HttpServletRequest");
|
||||
|
||||
RequestPart requestPart = parameter.getParameterAnnotation(RequestPart.class);
|
||||
boolean isRequired = ((requestPart == null || requestPart.required()) && !parameter.isOptional());
|
||||
|
||||
@@ -125,21 +129,20 @@ public class RequestPartMethodArgumentResolver extends AbstractMessageConverterM
|
||||
try {
|
||||
HttpInputMessage inputMessage = new RequestPartServletServerHttpRequest(servletRequest, name);
|
||||
arg = readWithMessageConverters(inputMessage, parameter, parameter.getNestedGenericParameterType());
|
||||
WebDataBinder binder = binderFactory.createBinder(request, arg, name);
|
||||
if (arg != null) {
|
||||
validateIfApplicable(binder, parameter);
|
||||
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
|
||||
throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
|
||||
if (binderFactory != null) {
|
||||
WebDataBinder binder = binderFactory.createBinder(request, arg, name);
|
||||
if (arg != null) {
|
||||
validateIfApplicable(binder, parameter);
|
||||
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
|
||||
throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
|
||||
}
|
||||
}
|
||||
if (mavContainer != null) {
|
||||
mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
|
||||
}
|
||||
}
|
||||
mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
|
||||
}
|
||||
catch (MissingServletRequestPartException ex) {
|
||||
if (isRequired) {
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
catch (MultipartException ex) {
|
||||
catch (MissingServletRequestPartException | MultipartException ex) {
|
||||
if (isRequired) {
|
||||
throw ex;
|
||||
}
|
||||
@@ -157,7 +160,7 @@ public class RequestPartMethodArgumentResolver extends AbstractMessageConverterM
|
||||
return adaptArgumentIfNecessary(arg, parameter);
|
||||
}
|
||||
|
||||
private String getPartName(MethodParameter methodParam, RequestPart requestPart) {
|
||||
private String getPartName(MethodParameter methodParam, @Nullable RequestPart requestPart) {
|
||||
String partName = (requestPart != null ? requestPart.name() : "");
|
||||
if (partName.isEmpty()) {
|
||||
partName = methodParam.getParameterName();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -32,7 +32,6 @@ import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.method.ControllerAdviceBean;
|
||||
|
||||
|
||||
/**
|
||||
* Invokes {@link RequestBodyAdvice} and {@link ResponseBodyAdvice} where each
|
||||
* instance may be (and is most likely) wrapped with
|
||||
@@ -52,35 +51,20 @@ class RequestResponseBodyAdviceChain implements RequestBodyAdvice, ResponseBodyA
|
||||
* Create an instance from a list of objects that are either of type
|
||||
* {@code ControllerAdviceBean} or {@code RequestBodyAdvice}.
|
||||
*/
|
||||
public RequestResponseBodyAdviceChain(List<Object> requestResponseBodyAdvice) {
|
||||
initAdvice(requestResponseBodyAdvice);
|
||||
}
|
||||
|
||||
private void initAdvice(List<Object> requestResponseBodyAdvice) {
|
||||
if (requestResponseBodyAdvice == null) {
|
||||
return;
|
||||
}
|
||||
for (Object advice : requestResponseBodyAdvice) {
|
||||
Class<?> beanType = (advice instanceof ControllerAdviceBean ?
|
||||
((ControllerAdviceBean) advice).getBeanType() : advice.getClass());
|
||||
if (RequestBodyAdvice.class.isAssignableFrom(beanType)) {
|
||||
this.requestBodyAdvice.add(advice);
|
||||
public RequestResponseBodyAdviceChain(@Nullable List<Object> requestResponseBodyAdvice) {
|
||||
if (requestResponseBodyAdvice != null) {
|
||||
for (Object advice : requestResponseBodyAdvice) {
|
||||
Class<?> beanType = (advice instanceof ControllerAdviceBean ?
|
||||
((ControllerAdviceBean) advice).getBeanType() : advice.getClass());
|
||||
if (beanType != null) {
|
||||
if (RequestBodyAdvice.class.isAssignableFrom(beanType)) {
|
||||
this.requestBodyAdvice.add(advice);
|
||||
}
|
||||
else if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
|
||||
this.responseBodyAdvice.add(advice);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
|
||||
this.responseBodyAdvice.add(advice);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<Object> getAdvice(Class<?> adviceType) {
|
||||
if (RequestBodyAdvice.class == adviceType) {
|
||||
return this.requestBodyAdvice;
|
||||
}
|
||||
else if (ResponseBodyAdvice.class == adviceType) {
|
||||
return this.responseBodyAdvice;
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Unexpected adviceType: " + adviceType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,18 +79,6 @@ class RequestResponseBodyAdviceChain implements RequestBodyAdvice, ResponseBodyA
|
||||
throw new UnsupportedOperationException("Not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object handleEmptyBody(@Nullable Object body, HttpInputMessage inputMessage, MethodParameter parameter,
|
||||
Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
|
||||
|
||||
for (RequestBodyAdvice advice : getMatchingAdvice(parameter, RequestBodyAdvice.class)) {
|
||||
if (advice.supports(parameter, targetType, converterType)) {
|
||||
body = advice.handleEmptyBody(body, inputMessage, parameter, targetType, converterType);
|
||||
}
|
||||
}
|
||||
return body;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpInputMessage beforeBodyRead(HttpInputMessage request, MethodParameter parameter,
|
||||
Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
|
||||
@@ -132,15 +104,29 @@ class RequestResponseBodyAdviceChain implements RequestBodyAdvice, ResponseBodyA
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType contentType,
|
||||
public Object beforeBodyWrite(@Nullable Object body, MethodParameter returnType, MediaType contentType,
|
||||
Class<? extends HttpMessageConverter<?>> converterType,
|
||||
ServerHttpRequest request, ServerHttpResponse response) {
|
||||
|
||||
return processBody(body, returnType, contentType, converterType, request, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object handleEmptyBody(@Nullable Object body, HttpInputMessage inputMessage, MethodParameter parameter,
|
||||
Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
|
||||
|
||||
for (RequestBodyAdvice advice : getMatchingAdvice(parameter, RequestBodyAdvice.class)) {
|
||||
if (advice.supports(parameter, targetType, converterType)) {
|
||||
body = advice.handleEmptyBody(body, inputMessage, parameter, targetType, converterType);
|
||||
}
|
||||
}
|
||||
return body;
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> Object processBody(Object body, MethodParameter returnType, MediaType contentType,
|
||||
@Nullable
|
||||
private <T> Object processBody(@Nullable Object body, MethodParameter returnType, MediaType contentType,
|
||||
Class<? extends HttpMessageConverter<?>> converterType,
|
||||
ServerHttpRequest request, ServerHttpResponse response) {
|
||||
|
||||
@@ -175,4 +161,16 @@ class RequestResponseBodyAdviceChain implements RequestBodyAdvice, ResponseBodyA
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<Object> getAdvice(Class<?> adviceType) {
|
||||
if (RequestBodyAdvice.class == adviceType) {
|
||||
return this.requestBodyAdvice;
|
||||
}
|
||||
else if (ResponseBodyAdvice.class == adviceType) {
|
||||
return this.responseBodyAdvice;
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Unexpected adviceType: " + adviceType);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -30,6 +30,7 @@ import org.springframework.http.converter.HttpMessageNotWritableException;
|
||||
import org.springframework.http.server.ServletServerHttpRequest;
|
||||
import org.springframework.http.server.ServletServerHttpResponse;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.HttpMediaTypeNotAcceptableException;
|
||||
import org.springframework.web.HttpMediaTypeNotSupportedException;
|
||||
@@ -76,7 +77,7 @@ public class RequestResponseBodyMethodProcessor extends AbstractMessageConverter
|
||||
* {@code ResponseBodyAdvice}.
|
||||
*/
|
||||
public RequestResponseBodyMethodProcessor(List<HttpMessageConverter<?>> converters,
|
||||
ContentNegotiationManager manager) {
|
||||
@Nullable ContentNegotiationManager manager) {
|
||||
|
||||
super(converters, manager);
|
||||
}
|
||||
@@ -122,48 +123,54 @@ public class RequestResponseBodyMethodProcessor extends AbstractMessageConverter
|
||||
* converter to read the content with.
|
||||
*/
|
||||
@Override
|
||||
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
|
||||
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
|
||||
|
||||
parameter = parameter.nestedIfOptional();
|
||||
Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
|
||||
String name = Conventions.getVariableNameForParameter(parameter);
|
||||
|
||||
WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
|
||||
if (arg != null) {
|
||||
validateIfApplicable(binder, parameter);
|
||||
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
|
||||
throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
|
||||
if (binderFactory != null) {
|
||||
WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
|
||||
if (arg != null) {
|
||||
validateIfApplicable(binder, parameter);
|
||||
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
|
||||
throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
|
||||
}
|
||||
}
|
||||
if (mavContainer != null) {
|
||||
mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
|
||||
}
|
||||
}
|
||||
mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
|
||||
|
||||
return adaptArgumentIfNecessary(arg, parameter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, @Nullable MethodParameter parameter,
|
||||
protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter,
|
||||
Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
|
||||
|
||||
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
|
||||
Assert.state(servletRequest != null, "No HttpServletRequest");
|
||||
ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest);
|
||||
|
||||
Object arg = readWithMessageConverters(inputMessage, parameter, paramType);
|
||||
if (arg == null) {
|
||||
if (checkRequired(parameter)) {
|
||||
throw new HttpMessageNotReadableException("Required request body is missing: " +
|
||||
parameter.getMethod().toGenericString());
|
||||
parameter.getExecutable().toGenericString());
|
||||
}
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
|
||||
protected boolean checkRequired(MethodParameter parameter) {
|
||||
return (parameter.getParameterAnnotation(RequestBody.class).required() && !parameter.isOptional());
|
||||
RequestBody requestBody = parameter.getParameterAnnotation(RequestBody.class);
|
||||
return (requestBody != null && requestBody.required() && !parameter.isOptional());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleReturnValue(Object returnValue, MethodParameter returnType,
|
||||
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
|
||||
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
|
||||
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.server.ServerHttpRequest;
|
||||
import org.springframework.http.server.ServerHttpResponse;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Allows customizing the response after the execution of an {@code @ResponseBody}
|
||||
@@ -58,7 +59,8 @@ public interface ResponseBodyAdvice<T> {
|
||||
* @param response the current response
|
||||
* @return the body that was passed in or a modified (possibly new) instance
|
||||
*/
|
||||
T beforeBodyWrite(T body, MethodParameter returnType, MediaType selectedContentType,
|
||||
@Nullable
|
||||
T beforeBodyWrite(@Nullable T body, MethodParameter returnType, MediaType selectedContentType,
|
||||
Class<? extends HttpMessageConverter<?>> selectedConverterType,
|
||||
ServerHttpRequest request, ServerHttpResponse response);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -162,24 +162,22 @@ public class ResponseBodyEmitter {
|
||||
sendInternal(object, mediaType);
|
||||
}
|
||||
|
||||
private void sendInternal(Object object, MediaType mediaType) throws IOException {
|
||||
if (object != null) {
|
||||
if (this.handler != null) {
|
||||
try {
|
||||
this.handler.send(object, mediaType);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
completeWithError(ex);
|
||||
throw ex;
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
completeWithError(ex);
|
||||
throw new IllegalStateException("Failed to send " + object, ex);
|
||||
}
|
||||
private void sendInternal(Object object, @Nullable MediaType mediaType) throws IOException {
|
||||
if (this.handler != null) {
|
||||
try {
|
||||
this.handler.send(object, mediaType);
|
||||
}
|
||||
else {
|
||||
this.earlySendAttempts.add(new DataWithMediaType(object, mediaType));
|
||||
catch (IOException ex) {
|
||||
completeWithError(ex);
|
||||
throw ex;
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
completeWithError(ex);
|
||||
throw new IllegalStateException("Failed to send " + object, ex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.earlySendAttempts.add(new DataWithMediaType(object, mediaType));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,7 +236,7 @@ public class ResponseBodyEmitter {
|
||||
*/
|
||||
interface Handler {
|
||||
|
||||
void send(Object data, MediaType mediaType) throws IOException;
|
||||
void send(Object data, @Nullable MediaType mediaType) throws IOException;
|
||||
|
||||
void complete();
|
||||
|
||||
@@ -260,7 +258,7 @@ public class ResponseBodyEmitter {
|
||||
|
||||
private final MediaType mediaType;
|
||||
|
||||
public DataWithMediaType(Object data, MediaType mediaType) {
|
||||
public DataWithMediaType(Object data, @Nullable MediaType mediaType) {
|
||||
this.data = data;
|
||||
this.mediaType = mediaType;
|
||||
}
|
||||
@@ -269,6 +267,7 @@ public class ResponseBodyEmitter {
|
||||
return this.data;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public MediaType getMediaType() {
|
||||
return this.mediaType;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.server.ServerHttpResponse;
|
||||
import org.springframework.http.server.ServletServerHttpResponse;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.accept.ContentNegotiationManager;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
@@ -110,7 +111,7 @@ public class ResponseBodyEmitterReturnValueHandler implements HandlerMethodRetur
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleReturnValue(Object returnValue, MethodParameter returnType,
|
||||
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
|
||||
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
|
||||
|
||||
if (returnValue == null) {
|
||||
@@ -119,6 +120,7 @@ public class ResponseBodyEmitterReturnValueHandler implements HandlerMethodRetur
|
||||
}
|
||||
|
||||
HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
|
||||
Assert.state(response != null, "No HttpServletResponse");
|
||||
ServerHttpResponse outputMessage = new ServletServerHttpResponse(response);
|
||||
|
||||
if (returnValue instanceof ResponseEntity) {
|
||||
@@ -135,6 +137,7 @@ public class ResponseBodyEmitterReturnValueHandler implements HandlerMethodRetur
|
||||
}
|
||||
|
||||
ServletRequest request = webRequest.getNativeRequest(ServletRequest.class);
|
||||
Assert.state(request != null, "No ServletRequest");
|
||||
ShallowEtagHeaderFilter.disableContentCaching(request);
|
||||
|
||||
ResponseBodyEmitter emitter;
|
||||
@@ -180,12 +183,12 @@ public class ResponseBodyEmitterReturnValueHandler implements HandlerMethodRetur
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(Object data, MediaType mediaType) throws IOException {
|
||||
public void send(Object data, @Nullable MediaType mediaType) throws IOException {
|
||||
sendInternal(data, mediaType);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> void sendInternal(T data, MediaType mediaType) throws IOException {
|
||||
private <T> void sendInternal(T data, @Nullable MediaType mediaType) throws IOException {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Writing [" + data + "]");
|
||||
}
|
||||
|
||||
@@ -120,6 +120,7 @@ public abstract class ResponseEntityExceptionHandler {
|
||||
NoHandlerFoundException.class,
|
||||
AsyncRequestTimeoutException.class
|
||||
})
|
||||
@Nullable
|
||||
public final ResponseEntity<Object> handleException(Exception ex, WebRequest request) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
if (ex instanceof HttpRequestMethodNotSupportedException) {
|
||||
@@ -452,10 +453,10 @@ public abstract class ResponseEntityExceptionHandler {
|
||||
AsyncRequestTimeoutException ex, HttpHeaders headers, HttpStatus status, WebRequest webRequest) {
|
||||
|
||||
if (webRequest instanceof ServletWebRequest) {
|
||||
ServletWebRequest servletRequest = (ServletWebRequest) webRequest;
|
||||
HttpServletRequest request = servletRequest.getNativeRequest(HttpServletRequest.class);
|
||||
HttpServletResponse response = servletRequest.getNativeResponse(HttpServletResponse.class);
|
||||
if (response.isCommitted()) {
|
||||
ServletWebRequest servletWebRequest = (ServletWebRequest) webRequest;
|
||||
HttpServletRequest request = servletWebRequest.getRequest();
|
||||
HttpServletResponse response = servletWebRequest.getResponse();
|
||||
if (response != null && response.isCommitted()) {
|
||||
if (logger.isErrorEnabled()) {
|
||||
logger.error("Async timeout for " + request.getMethod() + " [" + request.getRequestURI() + "]");
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -21,6 +21,8 @@ import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.method.annotation.AbstractCookieValueMethodArgumentResolver;
|
||||
import org.springframework.web.util.UrlPathHelper;
|
||||
@@ -38,7 +40,7 @@ public class ServletCookieValueMethodArgumentResolver extends AbstractCookieValu
|
||||
private UrlPathHelper urlPathHelper = new UrlPathHelper();
|
||||
|
||||
|
||||
public ServletCookieValueMethodArgumentResolver(ConfigurableBeanFactory beanFactory) {
|
||||
public ServletCookieValueMethodArgumentResolver(@Nullable ConfigurableBeanFactory beanFactory) {
|
||||
super(beanFactory);
|
||||
}
|
||||
|
||||
@@ -51,6 +53,8 @@ public class ServletCookieValueMethodArgumentResolver extends AbstractCookieValu
|
||||
@Override
|
||||
protected Object resolveName(String cookieName, MethodParameter parameter, NativeWebRequest webRequest) throws Exception {
|
||||
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
|
||||
Assert.state(servletRequest != null, "No HttpServletRequest");
|
||||
|
||||
Cookie cookieValue = WebUtils.getCookie(servletRequest, cookieName);
|
||||
if (Cookie.class.isAssignableFrom(parameter.getNestedParameterType())) {
|
||||
return cookieValue;
|
||||
|
||||
@@ -21,10 +21,12 @@ import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.concurrent.Callable;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
@@ -131,12 +133,15 @@ public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
|
||||
return;
|
||||
}
|
||||
|
||||
String reason = getResponseStatusReason();
|
||||
if (StringUtils.hasText(reason)) {
|
||||
webRequest.getResponse().sendError(status.value(), reason);
|
||||
}
|
||||
else {
|
||||
webRequest.getResponse().setStatus(status.value());
|
||||
HttpServletResponse response = webRequest.getResponse();
|
||||
if (response != null) {
|
||||
String reason = getResponseStatusReason();
|
||||
if (StringUtils.hasText(reason)) {
|
||||
response.sendError(status.value(), reason);
|
||||
}
|
||||
else {
|
||||
response.setStatus(status.value());
|
||||
}
|
||||
}
|
||||
|
||||
// To be picked up by RedirectView
|
||||
@@ -152,7 +157,7 @@ public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
|
||||
return webRequest.isNotModified();
|
||||
}
|
||||
|
||||
private String getReturnValueHandlingErrorMessage(String message, Object returnValue) {
|
||||
private String getReturnValueHandlingErrorMessage(String message, @Nullable Object returnValue) {
|
||||
StringBuilder sb = new StringBuilder(message);
|
||||
if (returnValue != null) {
|
||||
sb.append(" [type=").append(returnValue.getClass().getName()).append("]");
|
||||
@@ -213,7 +218,7 @@ public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
|
||||
* async return type, e.g. Foo instead of {@code DeferredResult<Foo>}.
|
||||
*/
|
||||
@Override
|
||||
public MethodParameter getReturnValueType(Object returnValue) {
|
||||
public MethodParameter getReturnValueType(@Nullable Object returnValue) {
|
||||
return this.returnType;
|
||||
}
|
||||
|
||||
@@ -266,7 +271,7 @@ public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
|
||||
return this.returnValue.getClass();
|
||||
}
|
||||
if (!ResolvableType.NONE.equals(this.returnType)) {
|
||||
return this.returnType.resolve();
|
||||
return this.returnType.resolve(Object.class);
|
||||
}
|
||||
return super.getParameterType();
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ package org.springframework.web.servlet.mvc.method.annotation;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
@@ -26,6 +25,7 @@ import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.DataBinder;
|
||||
import org.springframework.web.bind.ServletRequestDataBinder;
|
||||
@@ -152,6 +152,7 @@ public class ServletModelAttributeMethodProcessor extends ModelAttributeMethodPr
|
||||
@Override
|
||||
protected void bindRequestParameters(WebDataBinder binder, NativeWebRequest request) {
|
||||
ServletRequest servletRequest = request.getNativeRequest(ServletRequest.class);
|
||||
Assert.state(servletRequest != null, "No ServletRequest");
|
||||
ServletRequestDataBinder servletBinder = (ServletRequestDataBinder) binder;
|
||||
servletBinder.bind(servletRequest);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.
|
||||
@@ -38,7 +38,9 @@ public class ServletRequestDataBinderFactory extends InitBinderDataBinderFactory
|
||||
* @param binderMethods one or more {@code @InitBinder} methods
|
||||
* @param initializer provides global data binder initialization
|
||||
*/
|
||||
public ServletRequestDataBinderFactory(List<InvocableHandlerMethod> binderMethods, WebBindingInitializer initializer) {
|
||||
public ServletRequestDataBinderFactory(@Nullable List<InvocableHandlerMethod> binderMethods,
|
||||
@Nullable WebBindingInitializer initializer) {
|
||||
|
||||
super(binderMethods, initializer);
|
||||
}
|
||||
|
||||
@@ -46,7 +48,9 @@ public class ServletRequestDataBinderFactory extends InitBinderDataBinderFactory
|
||||
* Returns an instance of {@link ExtendedServletRequestDataBinder}.
|
||||
*/
|
||||
@Override
|
||||
protected ServletRequestDataBinder createBinderInstance(@Nullable Object target, String objectName, NativeWebRequest request) {
|
||||
protected ServletRequestDataBinder createBinderInstance(
|
||||
@Nullable Object target, @Nullable String objectName, NativeWebRequest request) throws Exception {
|
||||
|
||||
return new ExtendedServletRequestDataBinder(target, objectName);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.web.bind.support.WebDataBinderFactory;
|
||||
@@ -86,8 +87,8 @@ public class ServletRequestMethodArgumentResolver implements HandlerMethodArgume
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
|
||||
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
|
||||
|
||||
Class<?> paramType = parameter.getParameterType();
|
||||
|
||||
@@ -118,6 +119,7 @@ public class ServletRequestMethodArgumentResolver implements HandlerMethodArgume
|
||||
return nativeRequest;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Object resolveArgument(Class<?> paramType, HttpServletRequest request) throws IOException {
|
||||
if (HttpSession.class.isAssignableFrom(paramType)) {
|
||||
HttpSession session = request.getSession();
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.io.Writer;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.web.bind.support.WebDataBinderFactory;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||
@@ -57,8 +58,8 @@ public class ServletResponseMethodArgumentResolver implements HandlerMethodArgum
|
||||
* {@code null}, the request is considered directly handled.
|
||||
*/
|
||||
@Override
|
||||
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
|
||||
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
|
||||
|
||||
if (mavContainer != null) {
|
||||
mavContainer.setRequestHandled(true);
|
||||
|
||||
@@ -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.
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.web.servlet.mvc.method.annotation;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.support.WebArgumentResolver;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.context.request.RequestAttributes;
|
||||
@@ -45,10 +46,8 @@ public class ServletWebArgumentResolverAdapter extends AbstractWebArgumentResolv
|
||||
@Override
|
||||
protected NativeWebRequest getWebRequest() {
|
||||
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
|
||||
if (requestAttributes instanceof ServletRequestAttributes) {
|
||||
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
|
||||
return new ServletWebRequest(servletRequestAttributes.getRequest());
|
||||
}
|
||||
return null;
|
||||
Assert.state(requestAttributes instanceof ServletRequestAttributes, "No ServletRequestAttributes");
|
||||
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
|
||||
return new ServletWebRequest(servletRequestAttributes.getRequest());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 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.
|
||||
@@ -19,6 +19,7 @@ package org.springframework.web.servlet.mvc.method.annotation;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.ServletRequestBindingException;
|
||||
import org.springframework.web.bind.annotation.SessionAttribute;
|
||||
import org.springframework.web.bind.annotation.ValueConstants;
|
||||
@@ -42,6 +43,7 @@ public class SessionAttributeMethodArgumentResolver extends AbstractNamedValueMe
|
||||
@Override
|
||||
protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
|
||||
SessionAttribute ann = parameter.getParameterAnnotation(SessionAttribute.class);
|
||||
Assert.state(ann != null, "No SessionAttribute annotation");
|
||||
return new NamedValueInfo(ann.name(), ann.required(), ValueConstants.DEFAULT_NONE);
|
||||
}
|
||||
|
||||
|
||||
@@ -105,16 +105,13 @@ public class SseEmitter extends ResponseBodyEmitter {
|
||||
*/
|
||||
@Override
|
||||
public void send(Object object, @Nullable MediaType mediaType) throws IOException {
|
||||
if (object != null) {
|
||||
send(event().data(object, mediaType));
|
||||
}
|
||||
send(event().data(object, mediaType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an SSE event prepared with the given builder. For example:
|
||||
* <pre>
|
||||
* // static import of SseEmitter
|
||||
*
|
||||
* SseEmitter emitter = new SseEmitter();
|
||||
* emitter.send(event().name("update").id("1").data(myObject));
|
||||
* </pre>
|
||||
@@ -146,26 +143,26 @@ public class SseEmitter extends ResponseBodyEmitter {
|
||||
*/
|
||||
public interface SseEventBuilder {
|
||||
|
||||
/**
|
||||
* Add an SSE "comment" line.
|
||||
*/
|
||||
SseEventBuilder comment(String comment);
|
||||
|
||||
/**
|
||||
* Add an SSE "event" line.
|
||||
*/
|
||||
SseEventBuilder name(String eventName);
|
||||
|
||||
/**
|
||||
* Add an SSE "id" line.
|
||||
*/
|
||||
SseEventBuilder id(String id);
|
||||
|
||||
/**
|
||||
* Add an SSE "event" line.
|
||||
*/
|
||||
SseEventBuilder name(String eventName);
|
||||
|
||||
/**
|
||||
* Add an SSE "event" line.
|
||||
*/
|
||||
SseEventBuilder reconnectTime(long reconnectTimeMillis);
|
||||
|
||||
/**
|
||||
* Add an SSE "comment" line.
|
||||
*/
|
||||
SseEventBuilder comment(String comment);
|
||||
|
||||
/**
|
||||
* Add an SSE "data" line.
|
||||
*/
|
||||
@@ -195,20 +192,14 @@ public class SseEmitter extends ResponseBodyEmitter {
|
||||
private StringBuilder sb;
|
||||
|
||||
@Override
|
||||
public SseEventBuilder comment(String comment) {
|
||||
append(":").append(comment != null ? comment : "").append("\n");
|
||||
public SseEventBuilder id(String id) {
|
||||
append("id:").append(id).append("\n");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SseEventBuilder name(String name) {
|
||||
append("event:").append(name != null ? name : "").append("\n");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SseEventBuilder id(String id) {
|
||||
append("id:").append(id != null ? id : "").append("\n");
|
||||
append("event:").append(name).append("\n");
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -218,6 +209,12 @@ public class SseEmitter extends ResponseBodyEmitter {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SseEventBuilder comment(String comment) {
|
||||
append(":").append(comment).append("\n");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SseEventBuilder data(Object object) {
|
||||
return data(object, null);
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.springframework.core.ResolvableType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.server.ServerHttpResponse;
|
||||
import org.springframework.http.server.ServletServerHttpResponse;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.context.request.async.WebAsyncUtils;
|
||||
@@ -56,7 +57,7 @@ public class StreamingResponseBodyReturnValueHandler implements HandlerMethodRet
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleReturnValue(Object returnValue, MethodParameter returnType,
|
||||
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
|
||||
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
|
||||
|
||||
if (returnValue == null) {
|
||||
@@ -65,6 +66,7 @@ public class StreamingResponseBodyReturnValueHandler implements HandlerMethodRet
|
||||
}
|
||||
|
||||
HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
|
||||
Assert.state(response != null, "No HttpServletResponse");
|
||||
ServerHttpResponse outputMessage = new ServletServerHttpResponse(response);
|
||||
|
||||
if (returnValue instanceof ResponseEntity) {
|
||||
@@ -80,6 +82,7 @@ public class StreamingResponseBodyReturnValueHandler implements HandlerMethodRet
|
||||
}
|
||||
|
||||
ServletRequest request = webRequest.getNativeRequest(ServletRequest.class);
|
||||
Assert.state(request != null, "No ServletRequest");
|
||||
ShallowEtagHeaderFilter.disableContentCaching(request);
|
||||
|
||||
Assert.isInstanceOf(StreamingResponseBody.class, returnValue, "StreamingResponseBody expected");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -19,6 +19,8 @@ package org.springframework.web.servlet.mvc.method.annotation;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.support.WebDataBinderFactory;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||
@@ -38,7 +40,6 @@ import org.springframework.web.util.UriComponentsBuilder;
|
||||
*/
|
||||
public class UriComponentsBuilderMethodArgumentResolver implements HandlerMethodArgumentResolver {
|
||||
|
||||
|
||||
@Override
|
||||
public boolean supportsParameter(MethodParameter parameter) {
|
||||
Class<?> type = parameter.getParameterType();
|
||||
@@ -46,10 +47,11 @@ public class UriComponentsBuilderMethodArgumentResolver implements HandlerMethod
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
|
||||
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
|
||||
|
||||
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
|
||||
Assert.state(request != null, "No HttpServletRequest");
|
||||
return ServletUriComponentsBuilder.fromServletMapping(request);
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.web.servlet.mvc.method.annotation;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
|
||||
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||
@@ -46,7 +47,7 @@ public class ViewMethodReturnValueHandler implements HandlerMethodReturnValueHan
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleReturnValue(Object returnValue, MethodParameter returnType,
|
||||
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
|
||||
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
|
||||
|
||||
if (returnValue == null) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -76,7 +76,7 @@ public class ViewNameMethodReturnValueHandler implements HandlerMethodReturnValu
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleReturnValue(Object returnValue, MethodParameter returnType,
|
||||
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
|
||||
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
|
||||
|
||||
if (returnValue instanceof CharSequence) {
|
||||
|
||||
@@ -18,7 +18,6 @@ package org.springframework.web.servlet.mvc.support;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
@@ -208,7 +207,7 @@ public class DefaultHandlerExceptionResolver extends AbstractHandlerExceptionRes
|
||||
* @throws IOException potentially thrown from response.sendError()
|
||||
*/
|
||||
protected ModelAndView handleHttpMediaTypeNotSupported(HttpMediaTypeNotSupportedException ex,
|
||||
HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
|
||||
HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException {
|
||||
|
||||
response.sendError(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);
|
||||
List<MediaType> mediaTypes = ex.getSupportedMediaTypes();
|
||||
@@ -232,7 +231,7 @@ public class DefaultHandlerExceptionResolver extends AbstractHandlerExceptionRes
|
||||
* @throws IOException potentially thrown from response.sendError()
|
||||
*/
|
||||
protected ModelAndView handleHttpMediaTypeNotAcceptable(HttpMediaTypeNotAcceptableException ex,
|
||||
HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
|
||||
HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException {
|
||||
|
||||
response.sendError(HttpServletResponse.SC_NOT_ACCEPTABLE);
|
||||
return new ModelAndView();
|
||||
@@ -252,7 +251,7 @@ public class DefaultHandlerExceptionResolver extends AbstractHandlerExceptionRes
|
||||
* @since 4.2
|
||||
*/
|
||||
protected ModelAndView handleMissingPathVariable(MissingPathVariableException ex,
|
||||
HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
|
||||
HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException {
|
||||
|
||||
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex.getMessage());
|
||||
return new ModelAndView();
|
||||
@@ -271,7 +270,7 @@ public class DefaultHandlerExceptionResolver extends AbstractHandlerExceptionRes
|
||||
* @throws IOException potentially thrown from response.sendError()
|
||||
*/
|
||||
protected ModelAndView handleMissingServletRequestParameter(MissingServletRequestParameterException ex,
|
||||
HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
|
||||
HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException {
|
||||
|
||||
response.sendError(HttpServletResponse.SC_BAD_REQUEST, ex.getMessage());
|
||||
return new ModelAndView();
|
||||
@@ -289,7 +288,7 @@ public class DefaultHandlerExceptionResolver extends AbstractHandlerExceptionRes
|
||||
* @throws IOException potentially thrown from response.sendError()
|
||||
*/
|
||||
protected ModelAndView handleServletRequestBindingException(ServletRequestBindingException ex,
|
||||
HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
|
||||
HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException {
|
||||
|
||||
response.sendError(HttpServletResponse.SC_BAD_REQUEST, ex.getMessage());
|
||||
return new ModelAndView();
|
||||
@@ -307,7 +306,7 @@ public class DefaultHandlerExceptionResolver extends AbstractHandlerExceptionRes
|
||||
* @throws IOException potentially thrown from response.sendError()
|
||||
*/
|
||||
protected ModelAndView handleConversionNotSupported(ConversionNotSupportedException ex,
|
||||
HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
|
||||
HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException {
|
||||
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Failed to convert request element: " + ex);
|
||||
@@ -328,7 +327,7 @@ public class DefaultHandlerExceptionResolver extends AbstractHandlerExceptionRes
|
||||
* @throws IOException potentially thrown from response.sendError()
|
||||
*/
|
||||
protected ModelAndView handleTypeMismatch(TypeMismatchException ex,
|
||||
HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
|
||||
HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException {
|
||||
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Failed to bind request element: " + ex);
|
||||
@@ -351,7 +350,7 @@ public class DefaultHandlerExceptionResolver extends AbstractHandlerExceptionRes
|
||||
* @throws IOException potentially thrown from response.sendError()
|
||||
*/
|
||||
protected ModelAndView handleHttpMessageNotReadable(HttpMessageNotReadableException ex,
|
||||
HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
|
||||
HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException {
|
||||
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Failed to read HTTP message: " + ex);
|
||||
@@ -374,7 +373,7 @@ public class DefaultHandlerExceptionResolver extends AbstractHandlerExceptionRes
|
||||
* @throws IOException potentially thrown from response.sendError()
|
||||
*/
|
||||
protected ModelAndView handleHttpMessageNotWritable(HttpMessageNotWritableException ex,
|
||||
HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
|
||||
HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException {
|
||||
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Failed to write HTTP message: " + ex);
|
||||
@@ -394,7 +393,7 @@ public class DefaultHandlerExceptionResolver extends AbstractHandlerExceptionRes
|
||||
* @throws IOException potentially thrown from response.sendError()
|
||||
*/
|
||||
protected ModelAndView handleMethodArgumentNotValidException(MethodArgumentNotValidException ex,
|
||||
HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
|
||||
HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException {
|
||||
|
||||
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
|
||||
return new ModelAndView();
|
||||
@@ -411,7 +410,7 @@ public class DefaultHandlerExceptionResolver extends AbstractHandlerExceptionRes
|
||||
* @throws IOException potentially thrown from response.sendError()
|
||||
*/
|
||||
protected ModelAndView handleMissingServletRequestPartException(MissingServletRequestPartException ex,
|
||||
HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
|
||||
HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) throws IOException {
|
||||
|
||||
response.sendError(HttpServletResponse.SC_BAD_REQUEST, ex.getMessage());
|
||||
return new ModelAndView();
|
||||
@@ -429,7 +428,7 @@ public class DefaultHandlerExceptionResolver extends AbstractHandlerExceptionRes
|
||||
* @throws IOException potentially thrown from response.sendError()
|
||||
*/
|
||||
protected ModelAndView handleBindException(BindException ex, HttpServletRequest request,
|
||||
HttpServletResponse response, Object handler) throws IOException {
|
||||
HttpServletResponse response, @Nullable Object handler) throws IOException {
|
||||
|
||||
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
|
||||
return new ModelAndView();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user