@Nullable all the way: null-safety at field level

This commits extends nullability declarations to the field level, formalizing the interaction between methods and their underlying fields and therefore avoiding any nullability mismatch.

Issue: SPR-15720
This commit is contained in:
Juergen Hoeller
2017-06-30 01:53:45 +02:00
parent c4694c3f5c
commit cc74a2891a
936 changed files with 6090 additions and 2806 deletions

View File

@@ -307,30 +307,39 @@ public class DispatcherServlet extends FrameworkServlet {
private boolean cleanupAfterInclude = true;
/** MultipartResolver used by this servlet */
@Nullable
private MultipartResolver multipartResolver;
/** LocaleResolver used by this servlet */
@Nullable
private LocaleResolver localeResolver;
/** ThemeResolver used by this servlet */
@Nullable
private ThemeResolver themeResolver;
/** List of HandlerMappings used by this servlet */
@Nullable
private List<HandlerMapping> handlerMappings;
/** List of HandlerAdapters used by this servlet */
@Nullable
private List<HandlerAdapter> handlerAdapters;
/** List of HandlerExceptionResolvers used by this servlet */
@Nullable
private List<HandlerExceptionResolver> handlerExceptionResolvers;
/** RequestToViewNameTranslator used by this servlet */
@Nullable
private RequestToViewNameTranslator viewNameTranslator;
/** FlashMapManager used by this servlet */
@Nullable
private FlashMapManager flashMapManager;
/** List of ViewResolvers used by this servlet */
@Nullable
private List<ViewResolver> viewResolvers;
@@ -893,12 +902,14 @@ public class DispatcherServlet extends FrameworkServlet {
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
if (this.flashMapManager != null) {
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
try {
doDispatch(request, response);
@@ -941,7 +952,7 @@ public class DispatcherServlet extends FrameworkServlet {
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
@@ -1076,11 +1087,12 @@ public class DispatcherServlet extends FrameworkServlet {
*/
@Override
protected LocaleContext buildLocaleContext(final HttpServletRequest request) {
if (this.localeResolver instanceof LocaleContextResolver) {
return ((LocaleContextResolver) this.localeResolver).resolveLocaleContext(request);
LocaleResolver lr = this.localeResolver;
if (lr instanceof LocaleContextResolver) {
return ((LocaleContextResolver) lr).resolveLocaleContext(request);
}
else {
return () -> localeResolver.resolveLocale(request);
return () -> (lr != null ? lr.resolveLocale(request) : request.getLocale());
}
}
@@ -1140,10 +1152,12 @@ public class DispatcherServlet extends FrameworkServlet {
* @see MultipartResolver#cleanupMultipart
*/
protected void cleanupMultipart(HttpServletRequest request) {
MultipartHttpServletRequest multipartRequest =
WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class);
if (multipartRequest != null) {
this.multipartResolver.cleanupMultipart(multipartRequest);
if (this.multipartResolver != null) {
MultipartHttpServletRequest multipartRequest =
WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class);
if (multipartRequest != null) {
this.multipartResolver.cleanupMultipart(multipartRequest);
}
}
}
@@ -1155,14 +1169,16 @@ public class DispatcherServlet extends FrameworkServlet {
*/
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
if (this.handlerMappings != null) {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
@@ -1194,12 +1210,14 @@ public class DispatcherServlet extends FrameworkServlet {
* @throws ServletException if no HandlerAdapter can be found for the handler. This is a fatal error.
*/
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
if (ha.supports(handler)) {
return ha;
if (this.handlerAdapters != null) {
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
if (ha.supports(handler)) {
return ha;
}
}
}
throw new ServletException("No adapter for handler [" + handler +
@@ -1222,10 +1240,12 @@ public class DispatcherServlet extends FrameworkServlet {
// Check registered HandlerExceptionResolvers...
ModelAndView exMv = null;
for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) {
exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);
if (exMv != null) {
break;
if (this.handlerExceptionResolvers != null) {
for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) {
exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);
if (exMv != null) {
break;
}
}
}
if (exMv != null) {
@@ -1261,7 +1281,8 @@ public class DispatcherServlet extends FrameworkServlet {
*/
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Determine locale for request and apply it to the response.
Locale locale = this.localeResolver.resolveLocale(request);
Locale locale =
(this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
response.setLocale(locale);
View view;
@@ -1310,7 +1331,7 @@ public class DispatcherServlet extends FrameworkServlet {
*/
@Nullable
protected String getDefaultViewName(HttpServletRequest request) throws Exception {
return this.viewNameTranslator.getViewName(request);
return (this.viewNameTranslator != null ? this.viewNameTranslator.getViewName(request) : null);
}
/**
@@ -1331,10 +1352,12 @@ public class DispatcherServlet extends FrameworkServlet {
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);
if (view != null) {
return view;
if (this.viewResolvers != null) {
for (ViewResolver viewResolver : this.viewResolvers) {
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
return view;
}
}
}
return null;

View File

@@ -49,6 +49,7 @@ import org.springframework.util.StringUtils;
@SuppressWarnings("serial")
public final class FlashMap extends HashMap<String, Object> implements Comparable<FlashMap> {
@Nullable
private String targetRequestPath;
private final MultiValueMap<String, String> targetRequestParams = new LinkedMultiValueMap<>(4);
@@ -90,8 +91,8 @@ public final class FlashMap extends HashMap<String, Object> implements Comparabl
/**
* Provide a request parameter identifying the request for this FlashMap.
* @param name the expected parameter name (skipped if empty or {@code null})
* @param value the expected value (skipped if empty or {@code null})
* @param name the expected parameter name (skipped if empty)
* @param value the expected value (skipped if empty)
*/
public FlashMap addTargetRequestParam(String name, String value) {
if (StringUtils.hasText(name) && StringUtils.hasText(value)) {

View File

@@ -164,18 +164,22 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic
/** ServletContext attribute to find the WebApplicationContext in */
@Nullable
private String contextAttribute;
/** WebApplicationContext implementation class to create */
private Class<?> contextClass = DEFAULT_CONTEXT_CLASS;
/** WebApplicationContext id to assign */
@Nullable
private String contextId;
/** Namespace for this servlet */
@Nullable
private String namespace;
/** Explicit context config location */
@Nullable
private String contextConfigLocation;
/** Actual ApplicationContextInitializer instances to apply to the context */
@@ -183,6 +187,7 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic
new ArrayList<>();
/** Comma-delimited ApplicationContextInitializer class names set through init param */
@Nullable
private String contextInitializerClasses;
/** Should we publish the context as a ServletContext attribute? */
@@ -201,6 +206,7 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic
private boolean dispatchTraceRequest = false;
/** WebApplicationContext for this servlet */
@Nullable
private WebApplicationContext webApplicationContext;
/** If the WebApplicationContext was injected via {@link #setApplicationContext} */
@@ -769,6 +775,7 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic
/**
* Return this servlet's WebApplicationContext.
*/
@Nullable
public final WebApplicationContext getWebApplicationContext() {
return this.webApplicationContext;
}
@@ -1065,7 +1072,7 @@ public abstract class FrameworkServlet extends HttpServletBean implements Applic
private void publishRequestHandledEvent(HttpServletRequest request, HttpServletResponse response,
long startTime, @Nullable Throwable failureCause) {
if (this.publishEvents) {
if (this.publishEvents && this.webApplicationContext != null) {
// Whether or not we succeeded, publish an event.
long processingTime = System.currentTimeMillis() - startTime;
this.webApplicationContext.publishEvent(

View File

@@ -42,8 +42,10 @@ public class HandlerExecutionChain {
private final Object handler;
@Nullable
private HandlerInterceptor[] interceptors;
@Nullable
private List<HandlerInterceptor> interceptorList;
private int interceptorIndex = -1;
@@ -53,7 +55,7 @@ public class HandlerExecutionChain {
* Create a new HandlerExecutionChain.
* @param handler the handler object to execute
*/
public HandlerExecutionChain(@Nullable Object handler) {
public HandlerExecutionChain(Object handler) {
this(handler, (HandlerInterceptor[]) null);
}
@@ -63,7 +65,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, @Nullable HandlerInterceptor... interceptors) {
public HandlerExecutionChain(Object handler, @Nullable HandlerInterceptor... interceptors) {
if (handler instanceof HandlerExecutionChain) {
HandlerExecutionChain originalChain = (HandlerExecutionChain) handler;
this.handler = originalChain.getHandler();
@@ -80,9 +82,7 @@ public class HandlerExecutionChain {
/**
* Return the handler object to execute.
* @return the handler object (may be {@code null})
*/
@Nullable
public Object getHandler() {
return this.handler;
}
@@ -207,9 +207,6 @@ public class HandlerExecutionChain {
@Override
public String toString() {
Object handler = getHandler();
if (handler == null) {
return "HandlerExecutionChain with no handler";
}
StringBuilder sb = new StringBuilder();
sb.append("HandlerExecutionChain with handler [").append(handler).append("]");
HandlerInterceptor[] interceptors = getInterceptors();

View File

@@ -84,6 +84,7 @@ public abstract class HttpServletBean extends HttpServlet implements Environment
/** Logger available to subclasses */
protected final Log logger = LogFactory.getLog(getClass());
@Nullable
private ConfigurableEnvironment environment;
private final Set<String> requiredProperties = new HashSet<>(4);

View File

@@ -47,12 +47,15 @@ import org.springframework.util.CollectionUtils;
public class ModelAndView {
/** View instance or view name String */
@Nullable
private Object view;
/** Model Map */
@Nullable
private ModelMap model;
/** Optional HTTP status for the response */
@Nullable
private HttpStatus status;
/** Indicates whether or not this instance has been cleared with a call to {@link #clear()} */

View File

@@ -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.
@@ -35,7 +35,7 @@ public interface RequestToViewNameTranslator {
* Translate the given {@link HttpServletRequest} into a view name.
* @param request the incoming {@link HttpServletRequest} providing
* the context from which a view name is to be resolved
* @return the view name (or {@code null} if no default found)
* @return the view name, or {@code null} if no default found
* @throws Exception if view name translation fails
*/
@Nullable

View File

@@ -24,6 +24,7 @@ import javax.servlet.http.HttpServletResponse;
import org.springframework.lang.Nullable;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.Assert;
import org.springframework.util.PathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.context.support.ServletContextResource;
@@ -103,14 +104,18 @@ public class ResourceServlet extends HttpServletBean {
public static final String RESOURCE_PARAM_NAME = "resource";
@Nullable
private String defaultUrl;
@Nullable
private String allowedResources;
@Nullable
private String contentType;
private boolean applyLastModified = false;
@Nullable
private PathMatcher pathMatcher;
private long startupTime;
@@ -267,9 +272,12 @@ public class ResourceServlet extends HttpServletBean {
StringUtils.tokenizeToStringArray(resourceUrl, RESOURCE_URL_DELIMITERS);
for (String url : resourceUrls) {
// check whether URL matches allowed resources
if (this.allowedResources != null && !this.pathMatcher.match(this.allowedResources, url)) {
throw new ServletException("Resource [" + url +
"] does not match allowed pattern [" + this.allowedResources + "]");
if (this.allowedResources != null) {
Assert.state(this.pathMatcher != null, "No PathMatcher available");
if (!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 [" + url + "]");

View File

@@ -96,8 +96,10 @@ public class ContentNegotiationConfigurer {
/**
* Class constructor with {@link javax.servlet.ServletContext}.
*/
public ContentNegotiationConfigurer(ServletContext servletContext) {
this.factory.setServletContext(servletContext);
public ContentNegotiationConfigurer(@Nullable ServletContext servletContext) {
if (servletContext != null) {
this.factory.setServletContext(servletContext);
}
}

View File

@@ -47,6 +47,7 @@ public class DefaultServletHandlerConfigurer {
private final ServletContext servletContext;
@Nullable
private DefaultServletHttpRequestHandler handler;

View File

@@ -20,7 +20,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.springframework.core.Ordered;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.PathMatcher;
import org.springframework.util.StringUtils;
@@ -44,6 +44,7 @@ public class InterceptorRegistration {
private int order = 0;
@Nullable
private PathMatcher pathMatcher;

View File

@@ -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.
@@ -18,6 +18,7 @@ package org.springframework.web.servlet.config.annotation;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.web.servlet.mvc.ParameterizableViewController;
import org.springframework.web.servlet.view.RedirectView;
@@ -49,7 +50,6 @@ public class RedirectViewControllerRegistration {
/**
* Set the specific redirect 3xx status code to use.
*
* <p>If not set, {@link org.springframework.web.servlet.view.RedirectView}
* will select {@code HttpStatus.MOVED_TEMPORARILY (302)} by default.
*/
@@ -63,7 +63,6 @@ public class RedirectViewControllerRegistration {
* Whether to interpret a given redirect URL that starts with a slash ("/")
* as relative to the current ServletContext, i.e. as relative to the web
* application root.
*
* <p>Default is {@code true}.
*/
public RedirectViewControllerRegistration setContextRelative(boolean contextRelative) {
@@ -74,7 +73,6 @@ public class RedirectViewControllerRegistration {
/**
* Whether to propagate the query parameters of the current request through
* to the target redirect URL.
*
* <p>Default is {@code false}.
*/
public RedirectViewControllerRegistration setKeepQueryParams(boolean propagate) {
@@ -82,7 +80,7 @@ public class RedirectViewControllerRegistration {
return this;
}
protected void setApplicationContext(ApplicationContext applicationContext) {
protected void setApplicationContext(@Nullable ApplicationContext applicationContext) {
this.controller.setApplicationContext(applicationContext);
this.redirectView.setApplicationContext(applicationContext);
}

View File

@@ -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,8 +22,9 @@ import java.util.List;
import org.springframework.cache.Cache;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.Assert;
import org.springframework.http.CacheControl;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.web.servlet.resource.PathResourceResolver;
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
@@ -43,10 +44,13 @@ public class ResourceHandlerRegistration {
private final List<Resource> locations = new ArrayList<>();
@Nullable
private Integer cachePeriod;
@Nullable
private CacheControl cacheControl;
@Nullable
private ResourceChainRegistration resourceChainRegistration;

View File

@@ -56,6 +56,7 @@ public class ResourceHandlerRegistry {
private final ApplicationContext applicationContext;
@Nullable
private final ContentNegotiationManager contentNegotiationManager;
private final List<ResourceHandlerRegistration> registrations = new ArrayList<>();
@@ -142,9 +143,11 @@ public class ResourceHandlerRegistry {
for (ResourceHandlerRegistration registration : this.registrations) {
for (String pathPattern : registration.getPathPatterns()) {
ResourceHttpRequestHandler handler = registration.getRequestHandler();
if (this.contentNegotiationManager != null) {
handler.setContentNegotiationManager(this.contentNegotiationManager);
}
handler.setServletContext(this.servletContext);
handler.setApplicationContext(this.applicationContext);
handler.setContentNegotiationManager(this.contentNegotiationManager);
try {
handler.afterPropertiesSet();
}

View File

@@ -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.
@@ -18,6 +18,7 @@ package org.springframework.web.servlet.config.annotation;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.web.servlet.RequestToViewNameTranslator;
import org.springframework.web.servlet.mvc.ParameterizableViewController;
@@ -44,7 +45,6 @@ public class ViewControllerRegistration {
/**
* Set the status code to set on the response. Optional.
*
* <p>If not set the response status will be 200 (OK).
*/
public ViewControllerRegistration setStatusCode(HttpStatus statusCode) {
@@ -54,19 +54,17 @@ public class ViewControllerRegistration {
/**
* Set the view name to return. Optional.
*
* <p>If not specified, the view controller will return {@code null} as the
* view name in which case the configured {@link RequestToViewNameTranslator}
* will select the view name. The {@code DefaultRequestToViewNameTranslator}
* for example translates "/foo/bar" to "foo/bar".
*
* @see org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
*/
public void setViewName(String viewName) {
this.controller.setViewName(viewName);
}
protected void setApplicationContext(ApplicationContext applicationContext) {
protected void setApplicationContext(@Nullable ApplicationContext applicationContext) {
this.controller.setApplicationContext(applicationContext);
}

View File

@@ -39,11 +39,11 @@ public class ViewControllerRegistry {
private final List<ViewControllerRegistration> registrations = new ArrayList<>(4);
private final List<RedirectViewControllerRegistration> redirectRegistrations =
new ArrayList<>(10);
private final List<RedirectViewControllerRegistration> redirectRegistrations = new ArrayList<>(10);
private int order = 1;
@Nullable
private ApplicationContext applicationContext;
@@ -97,7 +97,7 @@ public class ViewControllerRegistry {
this.order = order;
}
protected void setApplicationContext(ApplicationContext applicationContext) {
protected void setApplicationContext(@Nullable ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}

View File

@@ -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.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.context.ApplicationContext;
import org.springframework.core.Ordered;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.accept.ContentNegotiationManager;
@@ -53,14 +54,18 @@ import org.springframework.web.servlet.view.tiles3.TilesViewResolver;
*/
public class ViewResolverRegistry {
@Nullable
private ContentNegotiatingViewResolver contentNegotiatingResolver;
private final List<ViewResolver> viewResolvers = new ArrayList<>(4);
@Nullable
private Integer order;
@Nullable
private ContentNegotiationManager contentNegotiationManager;
@Nullable
private ApplicationContext applicationContext;
@@ -98,15 +103,14 @@ public class ViewResolverRegistry {
* media types requested by the client (e.g. in the Accept header).
* <p>If invoked multiple times the provided default views will be added to
* any other default views that may have been configured already.
*
* @see ContentNegotiatingViewResolver#setDefaultViews
*/
public void enableContentNegotiation(boolean useNotAcceptableStatus, View... defaultViews) {
initContentNegotiatingViewResolver(defaultViews);
this.contentNegotiatingResolver.setUseNotAcceptableStatusCode(useNotAcceptableStatus);
ContentNegotiatingViewResolver vr = initContentNegotiatingViewResolver(defaultViews);
vr.setUseNotAcceptableStatusCode(useNotAcceptableStatus);
}
private void initContentNegotiatingViewResolver(View[] defaultViews) {
private ContentNegotiatingViewResolver initContentNegotiatingViewResolver(View[] defaultViews) {
// ContentNegotiatingResolver in the registry: elevate its precedence!
this.order = (this.order != null ? this.order : Ordered.HIGHEST_PRECEDENCE);
@@ -123,8 +127,11 @@ public class ViewResolverRegistry {
this.contentNegotiatingResolver = new ContentNegotiatingViewResolver();
this.contentNegotiatingResolver.setDefaultViews(Arrays.asList(defaultViews));
this.contentNegotiatingResolver.setViewResolvers(this.viewResolvers);
this.contentNegotiatingResolver.setContentNegotiationManager(this.contentNegotiationManager);
if (this.contentNegotiationManager != null) {
this.contentNegotiatingResolver.setContentNegotiationManager(this.contentNegotiationManager);
}
}
return this.contentNegotiatingResolver;
}
/**
@@ -162,7 +169,7 @@ public class ViewResolverRegistry {
* {@link org.springframework.web.servlet.view.tiles3.TilesConfigurer} bean.
*/
public UrlBasedViewResolverRegistration tiles() {
if (this.applicationContext != null && !hasBeanOfType(TilesConfigurer.class)) {
if (!checkBeanOfType(TilesConfigurer.class)) {
throw new BeanInitializationException("In addition to a Tiles view resolver " +
"there must also be a single TilesConfigurer bean in this web application context " +
"(or its parent).");
@@ -179,7 +186,7 @@ public class ViewResolverRegistry {
* {@link org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer} bean.
*/
public UrlBasedViewResolverRegistration freeMarker() {
if (this.applicationContext != null && !hasBeanOfType(FreeMarkerConfigurer.class)) {
if (!checkBeanOfType(FreeMarkerConfigurer.class)) {
throw new BeanInitializationException("In addition to a FreeMarker view resolver " +
"there must also be a single FreeMarkerConfig bean in this web application context " +
"(or its parent): FreeMarkerConfigurer is the usual implementation. " +
@@ -195,7 +202,7 @@ public class ViewResolverRegistry {
* prefix and a default suffix of ".tpl".
*/
public UrlBasedViewResolverRegistration groovy() {
if (this.applicationContext != null && !hasBeanOfType(GroovyMarkupConfigurer.class)) {
if (!checkBeanOfType(GroovyMarkupConfigurer.class)) {
throw new BeanInitializationException("In addition to a Groovy markup view resolver " +
"there must also be a single GroovyMarkupConfig bean in this web application context " +
"(or its parent): GroovyMarkupConfigurer is the usual implementation. " +
@@ -211,7 +218,7 @@ public class ViewResolverRegistry {
* @since 4.2
*/
public UrlBasedViewResolverRegistration scriptTemplate() {
if (this.applicationContext != null && !hasBeanOfType(ScriptTemplateConfigurer.class)) {
if (!checkBeanOfType(ScriptTemplateConfigurer.class)) {
throw new BeanInitializationException("In addition to a script template view resolver " +
"there must also be a single ScriptTemplateConfig bean in this web application context " +
"(or its parent): ScriptTemplateConfigurer is the usual implementation. " +
@@ -262,11 +269,12 @@ public class ViewResolverRegistry {
this.order = order;
}
protected boolean hasBeanOfType(Class<?> beanType) {
return !ObjectUtils.isEmpty(BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.applicationContext, beanType, false, false));
}
private boolean checkBeanOfType(Class<?> beanType) {
return (this.applicationContext == null ||
!ObjectUtils.isEmpty(BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.applicationContext, beanType, false, false)));
}
protected int getOrder() {
return (this.order != null ? this.order : Ordered.LOWEST_PRECEDENCE);

View File

@@ -25,8 +25,6 @@ import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.BeanInitializationException;
@@ -58,6 +56,7 @@ import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConve
import org.springframework.http.converter.xml.SourceHttpMessageConverter;
import org.springframework.lang.Nullable;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.PathMatcher;
import org.springframework.validation.Errors;
@@ -198,22 +197,31 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
ClassUtils.isPresent("javax.json.bind.Jsonb", WebMvcConfigurationSupport.class.getClassLoader());
@Nullable
private ApplicationContext applicationContext;
@Nullable
private ServletContext servletContext;
@Nullable
private List<Object> interceptors;
@Nullable
private PathMatchConfigurer pathMatchConfigurer;
@Nullable
private ContentNegotiationManager contentNegotiationManager;
@Nullable
private List<HandlerMethodArgumentResolver> argumentResolvers;
@Nullable
private List<HandlerMethodReturnValueHandler> returnValueHandlers;
@Nullable
private List<HttpMessageConverter<?>> messageConverters;
@Nullable
private Map<String, CorsConfiguration> corsConfigurations;
@@ -229,7 +237,8 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
* Return the associated Spring {@link ApplicationContext}.
* @since 4.2
*/
public ApplicationContext getApplicationContext() {
@Nullable
public final ApplicationContext getApplicationContext() {
return this.applicationContext;
}
@@ -246,7 +255,8 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
* Return the associated {@link javax.servlet.ServletContext}.
* @since 4.2
*/
public ServletContext getServletContext() {
@Nullable
public final ServletContext getServletContext() {
return this.servletContext;
}
@@ -383,7 +393,7 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
try {
this.contentNegotiationManager = configurer.getContentNegotiationManager();
}
catch (Exception ex) {
catch (Throwable ex) {
throw new BeanInitializationException("Could not create ContentNegotiationManager", ex);
}
}
@@ -465,6 +475,9 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
*/
@Bean
public HandlerMapping resourceHandlerMapping() {
Assert.state(this.applicationContext != null, "No ApplicationContext set");
Assert.state(this.servletContext != null, "No ServletContext set");
ResourceHandlerRegistry registry = new ResourceHandlerRegistry(this.applicationContext,
this.servletContext, mvcContentNegotiationManager());
addResourceHandlers(registry);
@@ -514,7 +527,8 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
*/
@Bean
public HandlerMapping defaultServletHandlerMapping() {
DefaultServletHandlerConfigurer configurer = new DefaultServletHandlerConfigurer(servletContext);
Assert.state(this.servletContext != null, "No ServletContext set");
DefaultServletHandlerConfigurer configurer = new DefaultServletHandlerConfigurer(this.servletContext);
configureDefaultServletHandling(configurer);
AbstractHandlerMapping handlerMapping = configurer.getHandlerMapping();
handlerMapping = handlerMapping != null ? handlerMapping : new EmptyHandlerMapping();
@@ -785,16 +799,22 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
}
if (jackson2XmlPresent) {
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.xml().applicationContext(this.applicationContext).build();
messageConverters.add(new MappingJackson2XmlHttpMessageConverter(objectMapper));
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.xml();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2XmlHttpMessageConverter(builder.build()));
}
else if (jaxb2Present) {
messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
}
if (jackson2Present) {
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().applicationContext(this.applicationContext).build();
messageConverters.add(new MappingJackson2HttpMessageConverter(objectMapper));
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2HttpMessageConverter(builder.build()));
}
else if (gsonPresent) {
messageConverters.add(new GsonHttpMessageConverter());
@@ -804,12 +824,18 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
}
if (jackson2SmilePresent) {
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.smile().applicationContext(this.applicationContext).build();
messageConverters.add(new MappingJackson2SmileHttpMessageConverter(objectMapper));
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.smile();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2SmileHttpMessageConverter(builder.build()));
}
if (jackson2CborPresent) {
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.cbor().applicationContext(this.applicationContext).build();
messageConverters.add(new MappingJackson2CborHttpMessageConverter(objectMapper));
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.cbor();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2CborHttpMessageConverter(builder.build()));
}
}
@@ -911,7 +937,9 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
exceptionHandlerResolver.setResponseBodyAdvice(
Collections.singletonList(new JsonViewResponseBodyAdvice()));
}
exceptionHandlerResolver.setApplicationContext(this.applicationContext);
if (this.applicationContext != null) {
exceptionHandlerResolver.setApplicationContext(this.applicationContext);
}
exceptionHandlerResolver.afterPropertiesSet();
exceptionResolvers.add(exceptionHandlerResolver);
@@ -947,7 +975,9 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
public ViewResolver mvcViewResolver() {
ViewResolverRegistry registry = new ViewResolverRegistry();
registry.setContentNegotiationManager(mvcContentNegotiationManager());
registry.setApplicationContext(this.applicationContext);
if (this.applicationContext != null) {
registry.setApplicationContext(this.applicationContext);
}
configureViewResolvers(registry);
if (registry.getViewResolvers().isEmpty()) {
@@ -962,7 +992,9 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
composite.setOrder(registry.getOrder());
composite.setViewResolvers(registry.getViewResolvers());
composite.setApplicationContext(this.applicationContext);
composite.setServletContext(this.servletContext);
if (this.servletContext != null) {
composite.setServletContext(this.servletContext);
}
return composite;
}

View File

@@ -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,10 +51,13 @@ public abstract class AbstractHandlerExceptionResolver implements HandlerExcepti
private int order = Ordered.LOWEST_PRECEDENCE;
@Nullable
private Set<?> mappedHandlers;
@Nullable
private Class<?>[] mappedHandlerClasses;
@Nullable
private Log warnLogger;
private boolean preventResponseCaching = false;
@@ -101,7 +104,6 @@ public abstract class AbstractHandlerExceptionResolver implements HandlerExcepti
* <p>Default is no warn logging. Specify this setting to activate warn logging into a specific
* category. Alternatively, override the {@link #logException} method for custom logging.
* @see org.apache.commons.logging.LogFactory#getLog(String)
* @see org.apache.log4j.Logger#getLogger(String)
* @see java.util.logging.Logger#getLogger(String)
*/
public void setWarnLogCategory(String loggerName) {

View File

@@ -69,6 +69,7 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
private int order = Integer.MAX_VALUE; // default: same as non-Ordered
@Nullable
private Object defaultHandler;
private UrlPathHelper urlPathHelper = new UrlPathHelper();
@@ -481,6 +482,7 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
private class PreFlightHandler implements HttpRequestHandler, CorsConfigurationSource {
@Nullable
private final CorsConfiguration config;
public PreFlightHandler(@Nullable CorsConfiguration config) {
@@ -501,6 +503,7 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
private class CorsInterceptor extends HandlerInterceptorAdapter implements CorsConfigurationSource {
@Nullable
private final CorsConfiguration config;
public CorsInterceptor(@Nullable CorsConfiguration config) {

View File

@@ -88,6 +88,7 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
private boolean detectHandlerMethodsInAncestorContexts = false;
@Nullable
private HandlerMethodMappingNamingStrategy<T> namingStrategy;
private final MappingRegistry mappingRegistry = new MappingRegistry();
@@ -683,6 +684,7 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
private final List<String> directUrls;
@Nullable
private final String mappingName;
public MappingRegistration(T mapping, HandlerMethod handlerMethod,

View File

@@ -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.
@@ -34,18 +34,11 @@ import org.springframework.web.servlet.ModelAndView;
*/
public class HandlerExceptionResolverComposite implements HandlerExceptionResolver, Ordered {
@Nullable
private List<HandlerExceptionResolver> resolvers;
private int order = Ordered.LOWEST_PRECEDENCE;
public void setOrder(int order) {
this.order = order;
}
@Override
public int getOrder() {
return this.order;
}
/**
* Set the list of exception resolvers to delegate to.
@@ -58,21 +51,30 @@ public class HandlerExceptionResolverComposite implements HandlerExceptionResolv
* Return the list of exception resolvers to delegate to.
*/
public List<HandlerExceptionResolver> getExceptionResolvers() {
return Collections.unmodifiableList(resolvers);
return (this.resolvers != null ? Collections.unmodifiableList(this.resolvers) : Collections.emptyList());
}
public void setOrder(int order) {
this.order = order;
}
@Override
public int getOrder() {
return this.order;
}
/**
* Resolve the exception by iterating over the list of configured exception resolvers.
* The first one to return a ModelAndView instance wins. Otherwise {@code null} is returned.
*/
@Override
@Nullable
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response,
@Nullable Object handler,
Exception ex) {
if (resolvers != null) {
for (HandlerExceptionResolver handlerExceptionResolver : resolvers) {
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,
@Nullable Object handler,Exception ex) {
if (this.resolvers != null) {
for (HandlerExceptionResolver handlerExceptionResolver : this.resolvers) {
ModelAndView mav = handlerExceptionResolver.resolveException(request, response, handler, ex);
if (mav != null) {
return mav;

View File

@@ -45,12 +45,15 @@ import org.springframework.web.servlet.ModelAndView;
*/
public final class MappedInterceptor implements HandlerInterceptor {
@Nullable
private final String[] includePatterns;
@Nullable
private final String[] excludePatterns;
private final HandlerInterceptor interceptor;
@Nullable
private PathMatcher pathMatcher;

View File

@@ -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.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -49,16 +48,21 @@ public class SimpleMappingExceptionResolver extends AbstractHandlerExceptionReso
public static final String DEFAULT_EXCEPTION_ATTRIBUTE = "exception";
@Nullable
private Properties exceptionMappings;
@Nullable
private Class<?>[] excludedExceptions;
@Nullable
private String defaultErrorView;
@Nullable
private Integer defaultStatusCode;
private Map<String, Integer> statusCodes = new HashMap<>();
@Nullable
private String exceptionAttribute = DEFAULT_EXCEPTION_ATTRIBUTE;

View File

@@ -69,8 +69,10 @@ public class SimpleServletPostProcessor implements
private boolean useSharedServletConfig = true;
@Nullable
private ServletContext servletContext;
@Nullable
private ServletConfig servletConfig;
@@ -140,9 +142,10 @@ public class SimpleServletPostProcessor implements
private final String servletName;
@Nullable
private final ServletContext servletContext;
public DelegatingServletConfig(String servletName, ServletContext servletContext) {
public DelegatingServletConfig(String servletName, @Nullable ServletContext servletContext) {
this.servletName = servletName;
this.servletContext = servletContext;
}
@@ -153,6 +156,7 @@ public class SimpleServletPostProcessor implements
}
@Override
@Nullable
public ServletContext getServletContext() {
return this.servletContext;
}

View File

@@ -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.
@@ -21,6 +21,8 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.lang.Nullable;
/**
* Interceptor that checks the authorization of the current user via the
* user's roles, as evaluated by HttpServletRequest's isUserInRole method.
@@ -31,6 +33,7 @@ import javax.servlet.http.HttpServletResponse;
*/
public class UserRoleAuthorizationInterceptor extends HandlerInterceptorAdapter {
@Nullable
private String[] authorizedRoles;

View File

@@ -23,6 +23,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.util.WebUtils;
@@ -87,8 +88,10 @@ import org.springframework.web.util.WebUtils;
*/
public class ServletForwardingController extends AbstractController implements BeanNameAware {
@Nullable
private String servletName;
@Nullable
private String beanName;

View File

@@ -28,6 +28,7 @@ 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.Assert;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.servlet.ModelAndView;
@@ -84,14 +85,18 @@ import org.springframework.web.servlet.ModelAndView;
public class ServletWrappingController extends AbstractController
implements BeanNameAware, InitializingBean, DisposableBean {
@Nullable
private Class<? extends Servlet> servletClass;
@Nullable
private String servletName;
private Properties initParameters = new Properties();
@Nullable
private String beanName;
@Nullable
private Servlet servletInstance;
@@ -156,6 +161,7 @@ public class ServletWrappingController extends AbstractController
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
throws Exception {
Assert.state(this.servletInstance != null, "No Servlet instance");
this.servletInstance.service(request, response);
return null;
}
@@ -167,7 +173,9 @@ public class ServletWrappingController extends AbstractController
*/
@Override
public void destroy() {
this.servletInstance.destroy();
if (this.servletInstance != null) {
this.servletInstance.destroy();
}
}
@@ -179,6 +187,7 @@ public class ServletWrappingController extends AbstractController
private class DelegatingServletConfig implements ServletConfig {
@Override
@Nullable
public String getServletName() {
return servletName;
}

View File

@@ -17,7 +17,6 @@
package org.springframework.web.servlet.mvc.annotation;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -56,6 +55,7 @@ import org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver;
*/
public class ResponseStatusExceptionResolver extends AbstractHandlerExceptionResolver implements MessageSourceAware {
@Nullable
private MessageSource messageSource;

View File

@@ -18,6 +18,8 @@ package org.springframework.web.servlet.mvc.condition;
import javax.servlet.http.HttpServletRequest;
import org.springframework.lang.Nullable;
/**
* Supports "name=value" style expressions as described in:
* {@link org.springframework.web.bind.annotation.RequestMapping#params()} and
@@ -31,6 +33,7 @@ abstract class AbstractNameValueExpression<T> implements NameValueExpression<T>
protected final String name;
@Nullable
protected final T value;
protected final boolean isNegated;
@@ -40,12 +43,12 @@ abstract class AbstractNameValueExpression<T> implements NameValueExpression<T>
int separator = expression.indexOf('=');
if (separator == -1) {
this.isNegated = expression.startsWith("!");
this.name = isNegated ? expression.substring(1) : expression;
this.name = (this.isNegated ? expression.substring(1) : expression);
this.value = null;
}
else {
this.isNegated = (separator > 0) && (expression.charAt(separator - 1) == '!');
this.name = isNegated ? expression.substring(0, separator - 1) : expression.substring(0, separator);
this.name = (this.isNegated ? expression.substring(0, separator - 1) : expression.substring(0, separator));
this.value = parseValue(expression.substring(separator + 1));
}
}

View File

@@ -23,7 +23,6 @@ import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import org.springframework.http.InvalidMediaTypeException;
@@ -90,7 +89,7 @@ public final class ConsumesRequestCondition extends AbstractRequestCondition<Con
if (headers != null) {
for (String header : headers) {
HeaderExpression expr = new HeaderExpression(header);
if ("Content-Type".equalsIgnoreCase(expr.name)) {
if ("Content-Type".equalsIgnoreCase(expr.name) && expr.value != null) {
for (MediaType mediaType : MediaType.parseMediaTypes(expr.value)) {
result.add(new ConsumeMediaTypeExpression(mediaType, expr.isNegated));
}

View File

@@ -22,6 +22,7 @@ import java.util.LinkedHashSet;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.cors.CorsUtils;
@@ -156,12 +157,12 @@ public final class HeadersRequestCondition extends AbstractRequestCondition<Head
@Override
protected boolean matchName(HttpServletRequest request) {
return request.getHeader(name) != null;
return (request.getHeader(this.name) != null);
}
@Override
protected boolean matchValue(HttpServletRequest request) {
return value.equals(request.getHeader(name));
return ObjectUtils.nullSafeEquals(this.value, request.getHeader(this.name));
}
}

View File

@@ -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.condition;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.annotation.RequestMapping;
/**
@@ -24,7 +25,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
*
* @author Rossen Stoyanchev
* @since 3.1
*
* @see RequestMapping#params()
* @see RequestMapping#headers()
*/
@@ -32,6 +32,7 @@ public interface NameValueExpression<T> {
String getName();
@Nullable
T getValue();
boolean isNegated();

View File

@@ -22,6 +22,7 @@ import java.util.LinkedHashSet;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.util.WebUtils;
@@ -141,12 +142,12 @@ public final class ParamsRequestCondition extends AbstractRequestCondition<Param
@Override
protected boolean matchName(HttpServletRequest request) {
return WebUtils.hasSubmitParameter(request, name);
return WebUtils.hasSubmitParameter(request, this.name);
}
@Override
protected boolean matchValue(HttpServletRequest request) {
return value.equals(request.getParameter(name));
return ObjectUtils.nullSafeEquals(this.value, request.getParameter(this.name));
}
}

View File

@@ -114,7 +114,7 @@ public final class ProducesRequestCondition extends AbstractRequestCondition<Pro
if (headers != null) {
for (String header : headers) {
HeaderExpression expr = new HeaderExpression(header);
if ("Accept".equalsIgnoreCase(expr.name)) {
if ("Accept".equalsIgnoreCase(expr.name) && expr.value != null) {
for (MediaType mediaType : MediaType.parseMediaTypes(expr.value)) {
result.add(new ProduceMediaTypeExpression(mediaType, expr.isNegated));
}

View File

@@ -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.
@@ -18,7 +18,6 @@ package org.springframework.web.servlet.mvc.condition;
import java.util.Collection;
import java.util.Collections;
import javax.servlet.http.HttpServletRequest;
import org.springframework.lang.Nullable;
@@ -39,6 +38,7 @@ import org.springframework.lang.Nullable;
*/
public final class RequestConditionHolder extends AbstractRequestCondition<RequestConditionHolder> {
@Nullable
private final RequestCondition<Object> condition;
@@ -87,7 +87,7 @@ public final class RequestConditionHolder extends AbstractRequestCondition<Reque
return this;
}
else {
assertEqualConditionTypes(other);
assertEqualConditionTypes(this.condition, other.condition);
RequestCondition<?> combined = (RequestCondition<?>) this.condition.combine(other.condition);
return new RequestConditionHolder(combined);
}
@@ -96,9 +96,9 @@ public final class RequestConditionHolder extends AbstractRequestCondition<Reque
/**
* Ensure the held request conditions are of the same type.
*/
private void assertEqualConditionTypes(RequestConditionHolder other) {
Class<?> clazz = this.condition.getClass();
Class<?> otherClazz = other.condition.getClass();
private void assertEqualConditionTypes(RequestCondition<?> thisCondition, RequestCondition<?> otherCondition) {
Class<?> clazz = thisCondition.getClass();
Class<?> otherClazz = otherCondition.getClass();
if (!clazz.equals(otherClazz)) {
throw new ClassCastException("Incompatible request conditions: " + clazz + " and " + otherClazz);
}
@@ -135,7 +135,7 @@ public final class RequestConditionHolder extends AbstractRequestCondition<Reque
return -1;
}
else {
assertEqualConditionTypes(other);
assertEqualConditionTypes(this.condition, other.condition);
return this.condition.compareTo(other.condition, request);
}
}

View File

@@ -53,6 +53,7 @@ import org.springframework.web.util.UrlPathHelper;
*/
public final class RequestMappingInfo implements RequestCondition<RequestMappingInfo> {
@Nullable
private final String name;
private final PatternsRequestCondition patternsCondition;
@@ -418,8 +419,10 @@ public final class RequestMappingInfo implements RequestCondition<RequestMapping
private String[] produces = new String[0];
@Nullable
private String mappingName;
@Nullable
private RequestCondition<?> customCondition;
private BuilderConfiguration options = new BuilderConfiguration();
@@ -511,8 +514,10 @@ public final class RequestMappingInfo implements RequestCondition<RequestMapping
*/
public static class BuilderConfiguration {
@Nullable
private UrlPathHelper urlPathHelper;
@Nullable
private PathMatcher pathMatcher;
private boolean trailingSlashMatch = true;
@@ -521,6 +526,7 @@ public final class RequestMappingInfo implements RequestCondition<RequestMapping
private boolean registeredSuffixPatternMatch = false;
@Nullable
private ContentNegotiationManager contentNegotiationManager;
/**
@@ -614,7 +620,7 @@ public final class RequestMappingInfo implements RequestCondition<RequestMapping
*/
@Nullable
public List<String> getFileExtensions() {
if (useRegisteredSuffixPatternMatch() && getContentNegotiationManager() != null) {
if (useRegisteredSuffixPatternMatch() && this.contentNegotiationManager != null) {
return this.contentNegotiationManager.getAllFileExtensions();
}
return null;

View File

@@ -49,6 +49,7 @@ import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StreamUtils;
import org.springframework.validation.Errors;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.HttpMediaTypeNotSupportedException;
@@ -302,6 +303,7 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements
private final HttpHeaders headers;
@Nullable
private final InputStream body;
public EmptyBodyCheckingHttpInputMessage(HttpInputMessage inputMessage) throws IOException {
@@ -332,7 +334,7 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements
@Override
public InputStream getBody() {
return this.body;
return (this.body != null ? this.body : StreamUtils.emptyInput());
}
public boolean hasBody() {

View File

@@ -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.
@@ -33,10 +33,11 @@ import org.springframework.web.method.support.ModelAndViewContainer;
*/
public class AsyncTaskMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
@Nullable
private final BeanFactory beanFactory;
public AsyncTaskMethodReturnValueHandler(BeanFactory beanFactory) {
public AsyncTaskMethodReturnValueHandler(@Nullable BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@@ -56,7 +57,9 @@ public class AsyncTaskMethodReturnValueHandler implements HandlerMethodReturnVal
}
WebAsyncTask<?> webAsyncTask = (WebAsyncTask<?>) returnValue;
webAsyncTask.setBeanFactory(this.beanFactory);
if (this.beanFactory != null) {
webAsyncTask.setBeanFactory(this.beanFactory);
}
WebAsyncUtils.getAsyncManager(webRequest).startCallableProcessing(webAsyncTask, mavContainer);
}

View File

@@ -75,12 +75,16 @@ import org.springframework.web.servlet.support.RequestContextUtils;
public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExceptionResolver
implements ApplicationContextAware, InitializingBean {
@Nullable
private List<HandlerMethodArgumentResolver> customArgumentResolvers;
@Nullable
private HandlerMethodArgumentResolverComposite argumentResolvers;
@Nullable
private List<HandlerMethodReturnValueHandler> customReturnValueHandlers;
@Nullable
private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
private List<HttpMessageConverter<?>> messageConverters;
@@ -89,6 +93,7 @@ public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExce
private final List<Object> responseBodyAdvice = new ArrayList<>();
@Nullable
private ApplicationContext applicationContext;
private final Map<Class<?>, ExceptionHandlerMethodResolver> exceptionHandlerCache =
@@ -374,8 +379,12 @@ public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExce
return null;
}
exceptionHandlerMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
exceptionHandlerMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
if (this.argumentResolvers != null) {
exceptionHandlerMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
exceptionHandlerMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
ServletWebRequest webRequest = new ServletWebRequest(request, response);
ModelAndViewContainer mavContainer = new ModelAndViewContainer();

View File

@@ -17,7 +17,6 @@
package org.springframework.web.servlet.mvc.method.annotation;
import java.util.Map;
import javax.servlet.ServletRequest;
import org.springframework.beans.MutablePropertyValues;
@@ -51,7 +50,7 @@ public class ExtendedServletRequestDataBinder extends ServletRequestDataBinder {
* @param objectName the name of the target object
* @see #DEFAULT_OBJECT_NAME
*/
public ExtendedServletRequestDataBinder(@Nullable Object target, @Nullable String objectName) {
public ExtendedServletRequestDataBinder(@Nullable Object target, String objectName) {
super(target, objectName);
}

View File

@@ -55,6 +55,7 @@ import org.springframework.web.servlet.mvc.annotation.ModelAndViewResolver;
*/
public class ModelAndViewResolverMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
@Nullable
private final List<ModelAndViewResolver> mavResolvers;
private final ModelAttributeMethodProcessor modelAttributeProcessor = new ModelAttributeMethodProcessor(true);

View File

@@ -717,21 +717,14 @@ public class MvcUriComponentsBuilder {
private static class ControllerMethodInvocationInterceptor
implements org.springframework.cglib.proxy.MethodInterceptor, MethodInterceptor {
private static final Method getControllerMethod =
ReflectionUtils.findMethod(MethodInvocationInfo.class, "getControllerMethod");
private static final Method getArgumentValues =
ReflectionUtils.findMethod(MethodInvocationInfo.class, "getArgumentValues");
private static final Method getControllerType =
ReflectionUtils.findMethod(MethodInvocationInfo.class, "getControllerType");
private final Class<?> controllerType;
@Nullable
private Method controllerMethod;
@Nullable
private Object[] argumentValues;
private Class<?> controllerType;
ControllerMethodInvocationInterceptor(Class<?> controllerType) {
this.controllerType = controllerType;
}
@@ -739,13 +732,13 @@ public class MvcUriComponentsBuilder {
@Override
@Nullable
public Object intercept(Object obj, Method method, Object[] args, @Nullable MethodProxy proxy) {
if (method.equals(getControllerMethod)) {
if (method.getName().equals("getControllerMethod")) {
return this.controllerMethod;
}
else if (method.equals(getArgumentValues)) {
else if (method.getName().equals("getArgumentValues")) {
return this.argumentValues;
}
else if (method.equals(getControllerType)) {
else if (method.getName().equals("getControllerType")) {
return this.controllerType;
}
else if (ReflectionUtils.isObjectMethod(method)) {

View File

@@ -180,10 +180,12 @@ class ReactiveTypeHandler {
private final TaskExecutor taskExecutor;
@Nullable
private Subscription subscription;
private final AtomicReference<Object> elementRef = new AtomicReference<>();
@Nullable
private Throwable error;
private volatile boolean terminated;
@@ -219,7 +221,7 @@ class ReactiveTypeHandler {
terminate();
this.emitter.complete();
});
this.emitter.onError(t -> this.emitter.completeWithError(t));
this.emitter.onError(this.emitter::completeWithError);
subscription.request(1);
}
@@ -276,6 +278,7 @@ class ReactiveTypeHandler {
Object element = this.elementRef.get();
if (element != null) {
this.elementRef.lazySet(null);
Assert.state(this.subscription != null, "No subscription");
try {
send(element);
this.subscription.request(1);
@@ -317,7 +320,9 @@ class ReactiveTypeHandler {
private void terminate() {
this.done = true;
this.subscription.cancel();
if (this.subscription != null) {
this.subscription.cancel();
}
}
}

View File

@@ -59,8 +59,8 @@ public class RedirectAttributesMethodArgumentResolver implements HandlerMethodAr
ModelMap redirectAttributes;
if (binderFactory != null) {
DataBinder dataBinder = binderFactory.createBinder(webRequest, null, null);
redirectAttributes = new RedirectAttributesModelMap(dataBinder);
DataBinder dataBinder = binderFactory.createBinder(webRequest, null, DataBinder.DEFAULT_OBJECT_NAME);
redirectAttributes = new RedirectAttributesModelMap(dataBinder);
}
else {
redirectAttributes = new RedirectAttributesModelMap();

View File

@@ -116,16 +116,22 @@ import org.springframework.web.util.WebUtils;
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
implements BeanFactoryAware, InitializingBean {
@Nullable
private List<HandlerMethodArgumentResolver> customArgumentResolvers;
@Nullable
private HandlerMethodArgumentResolverComposite argumentResolvers;
@Nullable
private HandlerMethodArgumentResolverComposite initBinderArgumentResolvers;
@Nullable
private List<HandlerMethodReturnValueHandler> customReturnValueHandlers;
@Nullable
private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
@Nullable
private List<ModelAndViewResolver> modelAndViewResolvers;
private ContentNegotiationManager contentNegotiationManager = new ContentNegotiationManager();
@@ -134,10 +140,12 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
private List<Object> requestResponseBodyAdvice = new ArrayList<>();
@Nullable
private WebBindingInitializer webBindingInitializer;
private AsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor("MvcAsync");
@Nullable
private Long asyncRequestTimeout;
private CallableProcessingInterceptor[] callableInterceptors = new CallableProcessingInterceptor[0];
@@ -156,21 +164,19 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
@Nullable
private ConfigurableBeanFactory beanFactory;
private final Map<Class<?>, SessionAttributesHandler> sessionAttributesHandlerCache =
new ConcurrentHashMap<>(64);
private final Map<Class<?>, SessionAttributesHandler> sessionAttributesHandlerCache = new ConcurrentHashMap<>(64);
private final Map<Class<?>, Set<Method>> initBinderCache = new ConcurrentHashMap<>(64);
private final Map<ControllerAdviceBean, Set<Method>> initBinderAdviceCache =
new LinkedHashMap<>();
private final Map<ControllerAdviceBean, Set<Method>> initBinderAdviceCache = new LinkedHashMap<>();
private final Map<Class<?>, Set<Method>> modelAttributeCache = new ConcurrentHashMap<>(64);
private final Map<ControllerAdviceBean, Set<Method>> modelAttributeAdviceCache =
new LinkedHashMap<>();
private final Map<ControllerAdviceBean, Set<Method>> modelAttributeAdviceCache = new LinkedHashMap<>();
public RequestMappingHandlerAdapter() {
@@ -284,7 +290,7 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
*/
@Nullable
public List<HandlerMethodReturnValueHandler> getReturnValueHandlers() {
return this.returnValueHandlers.getHandlers();
return (this.returnValueHandlers != null ? this.returnValueHandlers.getHandlers() : null);
}
/**
@@ -310,7 +316,7 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
*/
@Nullable
public List<ModelAndViewResolver> getModelAndViewResolvers() {
return modelAndViewResolvers;
return this.modelAndViewResolvers;
}
/**
@@ -827,8 +833,12 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
@@ -905,7 +915,9 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
private InvocableHandlerMethod createModelAttributeMethod(WebDataBinderFactory factory, Object bean, Method method) {
InvocableHandlerMethod attrMethod = new InvocableHandlerMethod(bean, method);
attrMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
if (this.argumentResolvers != null) {
attrMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
attrMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
attrMethod.setDataBinderFactory(factory);
return attrMethod;
@@ -937,7 +949,9 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
private InvocableHandlerMethod createInitBinderMethod(Object bean, Method method) {
InvocableHandlerMethod binderMethod = new InvocableHandlerMethod(bean, method);
binderMethod.setHandlerMethodArgumentResolvers(this.initBinderArgumentResolvers);
if (this.initBinderArgumentResolvers != null) {
binderMethod.setHandlerMethodArgumentResolvers(this.initBinderArgumentResolvers);
}
binderMethod.setDataBinderFactory(new DefaultDataBinderFactory(this.webBindingInitializer));
binderMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
return binderMethod;

View File

@@ -64,6 +64,7 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi
private ContentNegotiationManager contentNegotiationManager = new ContentNegotiationManager();
@Nullable
private StringValueResolver embeddedValueResolver;
private RequestMappingInfo.BuilderConfiguration config = new RequestMappingInfo.BuilderConfiguration();

View File

@@ -63,14 +63,17 @@ import org.springframework.util.ObjectUtils;
*/
public class ResponseBodyEmitter {
@Nullable
private final Long timeout;
private final Set<DataWithMediaType> earlySendAttempts = new LinkedHashSet<>(8);
@Nullable
private Handler handler;
private boolean complete;
@Nullable
private Throwable failure;
private final DefaultCallback timeoutCallback = new DefaultCallback();
@@ -270,6 +273,7 @@ public class ResponseBodyEmitter {
private final Object data;
@Nullable
private final MediaType mediaType;
public DataWithMediaType(Object data, @Nullable MediaType mediaType) {
@@ -290,6 +294,7 @@ public class ResponseBodyEmitter {
private class DefaultCallback implements Runnable {
@Nullable
private Runnable delegate;
public void setDelegate(Runnable delegate) {
@@ -308,6 +313,7 @@ public class ResponseBodyEmitter {
private class ErrorCallback implements Consumer<Throwable> {
@Nullable
private Consumer<Throwable> delegate;
public void setDelegate(Consumer<Throwable> callback) {

View File

@@ -27,6 +27,7 @@ import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.http.HttpStatus;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ResponseBody;
@@ -60,6 +61,7 @@ public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
private static final Method CALLABLE_METHOD = ClassUtils.getMethod(Callable.class, "call");
@Nullable
private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
@@ -112,6 +114,7 @@ public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
}
mavContainer.setRequestHandled(false);
Assert.state(this.returnValueHandlers != null, "No return value handlers");
try {
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
@@ -188,20 +191,19 @@ public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
private final MethodParameter returnType;
public ConcurrentResultHandlerMethod(final Object result, ConcurrentResultMethodParameter returnType) {
super(new Callable<Object>() {
@Override
public Object call() throws Exception {
if (result instanceof Exception) {
throw (Exception) result;
}
else if (result instanceof Throwable) {
throw new NestedServletException("Async processing failed", (Throwable) result);
}
return result;
super((Callable<Object>) () -> {
if (result instanceof Exception) {
throw (Exception) result;
}
else if (result instanceof Throwable) {
throw new NestedServletException("Async processing failed", (Throwable) result);
}
return result;
}, CALLABLE_METHOD);
setHandlerMethodReturnValueHandlers(ServletInvocableHandlerMethod.this.returnValueHandlers);
if (ServletInvocableHandlerMethod.this.returnValueHandlers != null) {
setHandlerMethodReturnValueHandlers(ServletInvocableHandlerMethod.this.returnValueHandlers);
}
this.returnType = returnType;
}
@@ -247,6 +249,7 @@ public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
*/
private class ConcurrentResultMethodParameter extends HandlerMethodParameter {
@Nullable
private final Object returnValue;
private final ResolvableType returnType;

View File

@@ -128,7 +128,7 @@ public class ServletModelAttributeMethodProcessor extends ModelAttributeMethodPr
* @throws Exception
*/
@Nullable
protected Object createAttributeFromRequestValue(String sourceValue, @Nullable String attributeName,
protected Object createAttributeFromRequestValue(String sourceValue, String attributeName,
MethodParameter methodParam, WebDataBinderFactory binderFactory, NativeWebRequest request)
throws Exception {

View File

@@ -49,7 +49,7 @@ public class ServletRequestDataBinderFactory extends InitBinderDataBinderFactory
*/
@Override
protected ServletRequestDataBinder createBinderInstance(
@Nullable Object target, @Nullable String objectName, NativeWebRequest request) throws Exception {
@Nullable Object target, String objectName, NativeWebRequest request) throws Exception {
return new ExtendedServletRequestDataBinder(target, objectName);
}

View File

@@ -65,6 +65,7 @@ import org.springframework.web.servlet.support.RequestContextUtils;
*/
public class ServletRequestMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Nullable
private static final Method newPushBuilderMethod =
ClassUtils.getMethodIfAvailable(HttpServletRequest.class, "newPushBuilder");

View File

@@ -189,6 +189,7 @@ public class SseEmitter extends ResponseBodyEmitter {
private final Set<DataWithMediaType> dataToSend = new LinkedHashSet<>(4);
@Nullable
private StringBuilder sb;
@Override

View File

@@ -35,6 +35,7 @@ import org.springframework.validation.DataBinder;
@SuppressWarnings("serial")
public class RedirectAttributesModelMap extends ModelMap implements RedirectAttributes {
@Nullable
private final DataBinder dataBinder;
private final ModelMap flashAttributes = new ModelMap();

View File

@@ -217,6 +217,7 @@ public class AppCacheManifestTransformer extends ResourceTransformerSupport {
private final String line;
@Nullable
private final Resource resource;
public LineOutput(String line, @Nullable Resource resource) {

View File

@@ -100,14 +100,19 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
private final List<ResourceTransformer> resourceTransformers = new ArrayList<>(4);
@Nullable
private ResourceHttpMessageConverter resourceHttpMessageConverter;
@Nullable
private ResourceRegionHttpMessageConverter resourceRegionHttpMessageConverter;
@Nullable
private ContentNegotiationManager contentNegotiationManager;
@Nullable
private PathExtensionContentNegotiationStrategy contentNegotiationStrategy;
@Nullable
private CorsConfiguration corsConfiguration;
@@ -176,14 +181,15 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
* <p>By default a {@link ResourceHttpMessageConverter} will be configured.
* @since 4.3
*/
public void setResourceHttpMessageConverter(ResourceHttpMessageConverter resourceHttpMessageConverter) {
this.resourceHttpMessageConverter = resourceHttpMessageConverter;
public void setResourceHttpMessageConverter(ResourceHttpMessageConverter messageConverter) {
this.resourceHttpMessageConverter = messageConverter;
}
/**
* Return the configured resource converter.
* @since 4.3
*/
@Nullable
public ResourceHttpMessageConverter getResourceHttpMessageConverter() {
return this.resourceHttpMessageConverter;
}
@@ -193,14 +199,15 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
* <p>By default a {@link ResourceRegionHttpMessageConverter} will be configured.
* @since 4.3
*/
public void setResourceRegionHttpMessageConverter(ResourceRegionHttpMessageConverter resourceRegionHttpMessageConverter) {
this.resourceRegionHttpMessageConverter = resourceRegionHttpMessageConverter;
public void setResourceRegionHttpMessageConverter(ResourceRegionHttpMessageConverter messageConverter) {
this.resourceRegionHttpMessageConverter = messageConverter;
}
/**
* Return the configured resource region converter.
* @since 4.3
*/
@Nullable
public ResourceRegionHttpMessageConverter getResourceRegionHttpMessageConverter() {
return this.resourceRegionHttpMessageConverter;
}
@@ -368,10 +375,12 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
ServletServerHttpResponse outputMessage = new ServletServerHttpResponse(response);
if (request.getHeader(HttpHeaders.RANGE) == null) {
Assert.state(this.resourceHttpMessageConverter != null, "Not initialized");
setHeaders(response, resource, mediaType);
this.resourceHttpMessageConverter.write(resource, mediaType, outputMessage);
}
else {
Assert.state(this.resourceRegionHttpMessageConverter != null, "Not initialized");
response.setHeader(HttpHeaders.ACCEPT_RANGES, "bytes");
ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(request);
try {
@@ -516,7 +525,8 @@ public class ResourceHttpRequestHandler extends WebContentGenerator
*/
@Nullable
protected MediaType getMediaType(HttpServletRequest request, Resource resource) {
return this.contentNegotiationStrategy.getMediaTypeForResource(resource);
return (this.contentNegotiationStrategy != null ?
this.contentNegotiationStrategy.getMediaTypeForResource(resource) : null);
}
/**

View File

@@ -35,6 +35,7 @@ import org.springframework.util.StringUtils;
*/
public abstract class ResourceTransformerSupport implements ResourceTransformer {
@Nullable
private ResourceUrlProvider resourceUrlProvider;
@@ -43,15 +44,15 @@ public abstract class ResourceTransformerSupport implements ResourceTransformer
* URL of links in a transformed resource (e.g. import links in a CSS file).
* This is required only for links expressed as full paths and not for
* relative links.
* @param resourceUrlProvider the URL provider to use
*/
public void setResourceUrlProvider(ResourceUrlProvider resourceUrlProvider) {
this.resourceUrlProvider = resourceUrlProvider;
}
/**
* @return the configured {@code ResourceUrlProvider}.
* Return the configured {@code ResourceUrlProvider}.
*/
@Nullable
public ResourceUrlProvider getResourceUrlProvider() {
return this.resourceUrlProvider;
}

View File

@@ -66,9 +66,10 @@ public class ResourceUrlEncodingFilter extends GenericFilterBean {
private final HttpServletRequest request;
/* Cache the index and prefix of the path within the DispatcherServlet mapping */
@Nullable
private Integer indexLookupPath;
private String prefixLookupPath;
private String prefixLookupPath = "";
public ResourceUrlEncodingResponseWrapper(HttpServletRequest request, HttpServletResponse wrapped) {
super(wrapped);
@@ -83,11 +84,11 @@ public class ResourceUrlEncodingFilter extends GenericFilterBean {
return super.encodeURL(url);
}
initLookupPath(resourceUrlProvider);
int index = initLookupPath(resourceUrlProvider);
if (url.startsWith(this.prefixLookupPath)) {
int suffixIndex = getQueryParamsIndex(url);
String suffix = url.substring(suffixIndex);
String lookupPath = url.substring(this.indexLookupPath, suffixIndex);
String lookupPath = url.substring(index, suffixIndex);
lookupPath = resourceUrlProvider.getForLookupPath(lookupPath);
if (lookupPath != null) {
return super.encodeURL(this.prefixLookupPath + lookupPath + suffix);
@@ -103,14 +104,13 @@ public class ResourceUrlEncodingFilter extends GenericFilterBean {
ResourceUrlProviderExposingInterceptor.RESOURCE_URL_PROVIDER_ATTR);
}
private void initLookupPath(ResourceUrlProvider urlProvider) {
private int initLookupPath(ResourceUrlProvider urlProvider) {
if (this.indexLookupPath == null) {
UrlPathHelper pathHelper = urlProvider.getUrlPathHelper();
String requestUri = pathHelper.getRequestUri(this.request);
String lookupPath = pathHelper.getLookupPathForRequest(this.request);
this.indexLookupPath = requestUri.lastIndexOf(lookupPath);
this.prefixLookupPath = requestUri.substring(0, this.indexLookupPath);
if ("/".equals(lookupPath) && !"/".equals(requestUri)) {
String contextPath = pathHelper.getContextPath(this.request);
if (requestUri.equals(contextPath)) {
@@ -119,6 +119,7 @@ public class ResourceUrlEncodingFilter extends GenericFilterBean {
}
}
}
return this.indexLookupPath;
}
private int getQueryParamsIndex(String url) {

View File

@@ -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,11 +20,12 @@ import java.io.IOException;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.lang.Nullable;
/**
* An extension of {@link org.springframework.core.io.ByteArrayResource}
* that a {@link ResourceTransformer} can use to represent an original
* resource preserving all other information except the content.
* An extension of {@link ByteArrayResource} that a {@link ResourceTransformer}
* can use to represent an original resource preserving all other information
* except the content.
*
* @author Jeremy Grelle
* @author Rossen Stoyanchev
@@ -32,6 +33,7 @@ import org.springframework.core.io.Resource;
*/
public class TransformedResource extends ByteArrayResource {
@Nullable
private final String filename;
private final long lastModified;

View File

@@ -24,6 +24,7 @@ import org.springframework.beans.BeanWrapper;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.context.NoSuchMessageException;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Errors;
@@ -54,24 +55,33 @@ public class BindStatus {
private final boolean htmlEscape;
@Nullable
private final String expression;
@Nullable
private final Errors errors;
@Nullable
private BindingResult bindingResult;
@Nullable
private Object value;
@Nullable
private Class<?> valueType;
@Nullable
private Object actualValue;
@Nullable
private PropertyEditor editor;
@Nullable
private List<? extends ObjectError> objectErrors;
private String[] errorCodes;
private String[] errorCodes = new String[0];
@Nullable
private String[] errorMessages;
@@ -133,7 +143,7 @@ public class BindStatus {
else {
this.objectErrors = this.errors.getGlobalErrors();
}
initErrorCodes();
initErrorCodes(this.objectErrors);
}
else {
@@ -163,27 +173,14 @@ public class BindStatus {
/**
* Extract the error codes from the ObjectError list.
*/
private void initErrorCodes() {
this.errorCodes = new String[this.objectErrors.size()];
for (int i = 0; i < this.objectErrors.size(); i++) {
ObjectError error = this.objectErrors.get(i);
private void initErrorCodes(List<? extends ObjectError> objectErrors) {
this.errorCodes = new String[objectErrors.size()];
for (int i = 0; i < objectErrors.size(); i++) {
ObjectError error = objectErrors.get(i);
this.errorCodes[i] = error.getCode();
}
}
/**
* Extract the error messages from the ObjectError list.
*/
private void initErrorMessages() throws NoSuchMessageException {
if (this.errorMessages == null) {
this.errorMessages = new String[this.objectErrors.size()];
for (int i = 0; i < this.objectErrors.size(); i++) {
ObjectError error = this.objectErrors.get(i);
this.errorMessages[i] = this.requestContext.getMessage(error, this.htmlEscape);
}
}
}
/**
* Return the bean and property path for which values and errors
@@ -256,14 +253,13 @@ public class BindStatus {
* Return if this status represents a field or object error.
*/
public boolean isError() {
return (this.errorCodes != null && this.errorCodes.length > 0);
return (this.errorCodes.length > 0);
}
/**
* Return the error codes for the field or object, if any.
* Returns an empty array instead of null if none.
*/
@Nullable
public String[] getErrorCodes() {
return this.errorCodes;
}
@@ -280,16 +276,15 @@ public class BindStatus {
* if any. Returns an empty array instead of null if none.
*/
public String[] getErrorMessages() {
initErrorMessages();
return this.errorMessages;
return initErrorMessages();
}
/**
* Return the first error message for the field or object, if any.
*/
public String getErrorMessage() {
initErrorMessages();
return (this.errorMessages.length > 0 ? this.errorMessages[0] : "");
String[] errorMessages = initErrorMessages();
return (errorMessages.length > 0 ? errorMessages[0] : "");
}
/**
@@ -299,8 +294,26 @@ public class BindStatus {
* @return the error message string
*/
public String getErrorMessagesAsString(String delimiter) {
initErrorMessages();
return StringUtils.arrayToDelimitedString(this.errorMessages, delimiter);
return StringUtils.arrayToDelimitedString(initErrorMessages(), delimiter);
}
/**
* Extract the error messages from the ObjectError list.
*/
private String[] initErrorMessages() throws NoSuchMessageException {
if (this.errorMessages == null) {
if (this.objectErrors != null) {
this.errorMessages = new String[this.objectErrors.size()];
for (int i = 0; i < this.objectErrors.size(); i++) {
ObjectError error = this.objectErrors.get(i);
this.errorMessages[i] = this.requestContext.getMessage(error, this.htmlEscape);
}
}
else {
this.errorMessages = new String[0];
}
}
return this.errorMessages;
}
/**
@@ -341,7 +354,7 @@ public class BindStatus {
StringBuilder sb = new StringBuilder("BindStatus: ");
sb.append("expression=[").append(this.expression).append("]; ");
sb.append("value=[").append(this.value).append("]");
if (isError()) {
if (!ObjectUtils.isEmpty(this.errorCodes)) {
sb.append("; errorCodes=").append(Arrays.asList(this.errorCodes));
}
return sb.toString();

View File

@@ -92,31 +92,43 @@ public class RequestContext {
public static final String WEB_APPLICATION_CONTEXT_ATTRIBUTE = RequestContext.class.getName() + ".CONTEXT";
protected static final boolean jstlPresent = ClassUtils.isPresent("javax.servlet.jsp.jstl.core.Config",
RequestContext.class.getClassLoader());
protected static final boolean jstlPresent = ClassUtils.isPresent(
"javax.servlet.jsp.jstl.core.Config", RequestContext.class.getClassLoader());
@Nullable
private HttpServletRequest request;
@Nullable
private HttpServletResponse response;
@Nullable
private Map<String, Object> model;
@Nullable
private WebApplicationContext webApplicationContext;
@Nullable
private Locale locale;
@Nullable
private TimeZone timeZone;
@Nullable
private Theme theme;
@Nullable
private Boolean defaultHtmlEscape;
@Nullable
private Boolean responseEncodedHtmlEscape;
@Nullable
private UrlPathHelper urlPathHelper;
@Nullable
private RequestDataValueProcessor requestDataValueProcessor;
@Nullable
private Map<String, Errors> errorsMap;
@@ -214,15 +226,15 @@ public class RequestContext {
* @param request current HTTP request
* @param servletContext the servlet context of the web application (can be {@code null}; necessary for
* fallback to root WebApplicationContext)
* @param model the model attributes for the current view (can be {@code null}, using the request attributes
* for Errors retrieval)
* @param model the model attributes for the current view (can be {@code null}, using the request
* attributes for Errors retrieval)
* @see #getFallbackLocale
* @see #getFallbackTheme
* @see org.springframework.web.servlet.DispatcherServlet#LOCALE_RESOLVER_ATTRIBUTE
* @see org.springframework.web.servlet.DispatcherServlet#THEME_RESOLVER_ATTRIBUTE
*/
protected void initContext(HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable ServletContext servletContext,
@Nullable Map<String, Object> model) {
protected void initContext(HttpServletRequest request, @Nullable HttpServletResponse response,
@Nullable ServletContext servletContext, @Nullable Map<String, Object> model) {
this.request = request;
this.response = response;
@@ -267,7 +279,8 @@ public class RequestContext {
// Determine response-encoded HTML escape setting from the "responseEncodedHtmlEscape"
// context-param in web.xml, if any.
this.responseEncodedHtmlEscape = WebUtils.getResponseEncodedHtmlEscape(this.webApplicationContext.getServletContext());
this.responseEncodedHtmlEscape =
WebUtils.getResponseEncodedHtmlEscape(this.webApplicationContext.getServletContext());
this.urlPathHelper = new UrlPathHelper();
@@ -776,8 +789,8 @@ public class RequestContext {
* @return the message
*/
public String getThemeMessage(String code, @Nullable List<?> args, String defaultMessage) {
return getTheme().getMessageSource().getMessage(code, (args != null ? args.toArray() : null), defaultMessage,
this.locale);
return getTheme().getMessageSource().getMessage(code, (args != null ? args.toArray() : null),
defaultMessage, this.locale);
}
/**

View File

@@ -50,6 +50,7 @@ import org.springframework.web.util.UrlPathHelper;
*/
public class ServletUriComponentsBuilder extends UriComponentsBuilder {
@Nullable
private String originalPath;

View File

@@ -30,6 +30,7 @@ import javax.servlet.http.HttpServletResponse;
import org.springframework.http.CacheControl;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.HttpRequestMethodNotSupportedException;
@@ -81,16 +82,20 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
/** Set of supported HTTP methods */
@Nullable
private Set<String> supportedMethods;
@Nullable
private String allowHeader;
private boolean requireSession = false;
@Nullable
private CacheControl cacheControl;
private int cacheSeconds = -1;
@Nullable
private String[] varyByRequestHeaders;
@@ -159,8 +164,9 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
/**
* Return the HTTP methods that this content generator supports.
*/
@Nullable
public final String[] getSupportedMethods() {
return StringUtils.toStringArray(this.supportedMethods);
return (this.supportedMethods != null ? StringUtils.toStringArray(this.supportedMethods) : null);
}
private void initAllowHeader() {
@@ -193,6 +199,7 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
* requests are handled before making a call to
* {@link #checkRequest(HttpServletRequest)}.
*/
@Nullable
protected String getAllowHeader() {
return this.allowHeader;
}
@@ -225,6 +232,7 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
* that builds the Cache-Control HTTP response header.
* @since 4.2
*/
@Nullable
public final CacheControl getCacheControl() {
return this.cacheControl;
}
@@ -269,6 +277,7 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
* Return the configured request header names for the "Vary" response header.
* @since 4.3
*/
@Nullable
public final String[] getVaryByRequestHeaders() {
return this.varyByRequestHeaders;
}
@@ -391,7 +400,7 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
applyCacheSeconds(response, this.cacheSeconds);
}
if (this.varyByRequestHeaders != null) {
for (String value : getVaryRequestHeadersToAdd(response)) {
for (String value : getVaryRequestHeadersToAdd(response, this.varyByRequestHeaders)) {
response.addHeader("Vary", value);
}
}
@@ -587,18 +596,18 @@ public abstract class WebContentGenerator extends WebApplicationObjectSupport {
}
private Collection<String> getVaryRequestHeadersToAdd(HttpServletResponse response) {
private Collection<String> getVaryRequestHeadersToAdd(HttpServletResponse response, String[] varyByRequestHeaders) {
if (!response.containsHeader(HttpHeaders.VARY)) {
return Arrays.asList(getVaryByRequestHeaders());
return Arrays.asList(varyByRequestHeaders);
}
Collection<String> result = new ArrayList<>(getVaryByRequestHeaders().length);
Collections.addAll(result, getVaryByRequestHeaders());
Collection<String> result = new ArrayList<>(varyByRequestHeaders.length);
Collections.addAll(result, varyByRequestHeaders);
for (String header : response.getHeaders(HttpHeaders.VARY)) {
for (String existing : StringUtils.tokenizeToStringArray(header, ",")) {
if ("*".equals(existing)) {
return Collections.emptyList();
}
for (String value : getVaryByRequestHeaders()) {
for (String value : varyByRequestHeaders) {
if (value.equalsIgnoreCase(existing)) {
result.remove(value);
}

View File

@@ -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.tags;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
import org.springframework.lang.Nullable;
/**
* JSP tag for collecting arguments and passing them to an {@link ArgumentAware}
* ancestor in the tag hierarchy.
@@ -33,6 +35,7 @@ import javax.servlet.jsp.tagext.BodyTagSupport;
@SuppressWarnings("serial")
public class ArgumentTag extends BodyTagSupport {
@Nullable
private Object value;
private boolean valueSet;

View File

@@ -20,6 +20,7 @@ import javax.servlet.ServletException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import org.springframework.lang.Nullable;
import org.springframework.validation.Errors;
/**
@@ -38,8 +39,9 @@ public class BindErrorsTag extends HtmlEscapingAwareTag {
public static final String ERRORS_VARIABLE_NAME = "errors";
private String name;
private String name = "";
@Nullable
private Errors errors;
@@ -80,6 +82,7 @@ public class BindErrorsTag extends HtmlEscapingAwareTag {
* Retrieve the Errors instance that this tag is currently bound to.
* <p>Intended for cooperating nesting tags.
*/
@Nullable
public final Errors getErrors() {
return this.errors;
}

View File

@@ -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.
@@ -17,11 +17,11 @@
package org.springframework.web.servlet.tags;
import java.beans.PropertyEditor;
import javax.servlet.jsp.JspTagException;
import javax.servlet.jsp.PageContext;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.validation.Errors;
import org.springframework.web.servlet.support.BindStatus;
@@ -55,14 +55,17 @@ public class BindTag extends HtmlEscapingAwareTag implements EditorAwareTag {
public static final String STATUS_VARIABLE_NAME = "status";
private String path;
private String path = "";
private boolean ignoreNestedPath = false;
@Nullable
private BindStatus status;
@Nullable
private Object previousPageStatus;
@Nullable
private Object previousRequestStatus;
@@ -150,6 +153,14 @@ public class BindTag extends HtmlEscapingAwareTag implements EditorAwareTag {
}
/**
* Return the current BindStatus.
*/
private BindStatus getStatus() {
Assert.state(this.status != null, "No current BindStatus");
return this.status;
}
/**
* Retrieve the property that this tag is currently bound to,
* or {@code null} if bound to an object rather than a specific property.
@@ -159,7 +170,7 @@ public class BindTag extends HtmlEscapingAwareTag implements EditorAwareTag {
*/
@Nullable
public final String getProperty() {
return this.status.getExpression();
return getStatus().getExpression();
}
/**
@@ -169,12 +180,12 @@ public class BindTag extends HtmlEscapingAwareTag implements EditorAwareTag {
*/
@Nullable
public final Errors getErrors() {
return this.status.getErrors();
return getStatus().getErrors();
}
@Override
public final PropertyEditor getEditor() {
return this.status.getEditor();
return getStatus().getEditor();
}

View File

@@ -59,8 +59,10 @@ public class EvalTag extends HtmlEscapingAwareTag {
private final ExpressionParser expressionParser = new SpelExpressionParser();
@Nullable
private Expression expression;
@Nullable
private String var;
private int scope = PageContext.PAGE_SCOPE;
@@ -114,12 +116,13 @@ public class EvalTag extends HtmlEscapingAwareTag {
this.pageContext.setAttribute(EVALUATION_CONTEXT_PAGE_ATTRIBUTE, evaluationContext);
}
if (this.var != null) {
Object result = this.expression.getValue(evaluationContext);
Object result = (this.expression != null ? this.expression.getValue(evaluationContext) : null);
this.pageContext.setAttribute(this.var, result, this.scope);
}
else {
try {
String result = this.expression.getValue(evaluationContext, String.class);
String result = (this.expression != null ?
this.expression.getValue(evaluationContext, String.class) : null);
result = ObjectUtils.getDisplayString(result);
result = htmlEscape(result);
result = (this.javaScriptEscape ? JavaScriptUtils.javaScriptEscape(result) : result);
@@ -156,6 +159,7 @@ public class EvalTag extends HtmlEscapingAwareTag {
private final PageContext pageContext;
@Nullable
private final javax.servlet.jsp.el.VariableResolver variableResolver;
public JspPropertyAccessor(PageContext pageContext) {

View File

@@ -18,6 +18,7 @@ package org.springframework.web.servlet.tags;
import javax.servlet.jsp.JspException;
import org.springframework.lang.Nullable;
import org.springframework.web.util.HtmlUtils;
/**
@@ -40,6 +41,7 @@ import org.springframework.web.util.HtmlUtils;
@SuppressWarnings("serial")
public abstract class HtmlEscapingAwareTag extends RequestContextAwareTag {
@Nullable
private Boolean htmlEscape;

View File

@@ -18,6 +18,7 @@ package org.springframework.web.servlet.tags;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import javax.servlet.jsp.JspException;
@@ -65,18 +66,23 @@ public class MessageTag extends HtmlEscapingAwareTag implements ArgumentAware {
public static final String DEFAULT_ARGUMENT_SEPARATOR = ",";
@Nullable
private MessageSourceResolvable message;
@Nullable
private String code;
@Nullable
private Object arguments;
private String argumentSeparator = DEFAULT_ARGUMENT_SEPARATOR;
private List<Object> nestedArguments;
private List<Object> nestedArguments = Collections.emptyList();
@Nullable
private String text;
@Nullable
private String var;
private String scope = TagUtils.SCOPE_PAGE;

View File

@@ -49,9 +49,11 @@ public class NestedPathTag extends TagSupport implements TryCatchFinally {
public static final String NESTED_PATH_VARIABLE_NAME = "nestedPath";
@Nullable
private String path;
/** Caching a previous nested path, so that it may be reset */
@Nullable
private String previousNestedPath;
@@ -74,6 +76,7 @@ public class NestedPathTag extends TagSupport implements TryCatchFinally {
/**
* Return the path that this tag applies to.
*/
@Nullable
public String getPath() {
return this.path;
}

View File

@@ -31,8 +31,10 @@ import org.springframework.lang.Nullable;
*/
public class Param {
@Nullable
private String name;
@Nullable
private String value;
@@ -46,6 +48,7 @@ public class Param {
/**
* Return the raw parameter name.
*/
@Nullable
public String getName() {
return this.name;
}
@@ -53,7 +56,7 @@ public class Param {
/**
* Set the raw value of the parameter
*/
public void setValue(String value) {
public void setValue(@Nullable String value) {
this.value = value;
}

View File

@@ -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.tags;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
import org.springframework.lang.Nullable;
/**
* JSP tag for collecting name-value parameters and passing them to a
* {@link ParamAware} ancestor in the tag hierarchy.
@@ -34,8 +36,9 @@ import javax.servlet.jsp.tagext.BodyTagSupport;
@SuppressWarnings("serial")
public class ParamTag extends BodyTagSupport {
private String name;
private String name = "";
@Nullable
private String value;
private boolean valueSet;
@@ -83,7 +86,7 @@ public class ParamTag extends BodyTagSupport {
@Override
public void release() {
super.release();
this.name = null;
this.name = "";
this.value = null;
this.valueSet = false;
}

View File

@@ -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.
@@ -24,6 +24,8 @@ import javax.servlet.jsp.tagext.TryCatchFinally;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.web.servlet.support.JspAwareRequestContext;
import org.springframework.web.servlet.support.RequestContext;
@@ -60,6 +62,7 @@ public abstract class RequestContextAwareTag extends TagSupport implements TryCa
protected final Log logger = LogFactory.getLog(getClass());
@Nullable
private RequestContext requestContext;
@@ -79,11 +82,7 @@ public abstract class RequestContextAwareTag extends TagSupport implements TryCa
}
return doStartTagInternal();
}
catch (JspException ex) {
logger.error(ex.getMessage(), ex);
throw ex;
}
catch (RuntimeException ex) {
catch (JspException | RuntimeException ex) {
logger.error(ex.getMessage(), ex);
throw ex;
}
@@ -97,6 +96,7 @@ public abstract class RequestContextAwareTag extends TagSupport implements TryCa
* Return the current RequestContext.
*/
protected final RequestContext getRequestContext() {
Assert.state(this.requestContext != null, "No current RequestContext");
return this.requestContext;
}

View File

@@ -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.
@@ -21,6 +21,7 @@ import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;
import org.springframework.lang.Nullable;
import org.springframework.web.util.TagUtils;
/**
@@ -41,9 +42,11 @@ import org.springframework.web.util.TagUtils;
public class TransformTag extends HtmlEscapingAwareTag {
/** the value to transform using the appropriate property editor */
@Nullable
private Object value;
/** the variable to put the result in */
@Nullable
private String var;
/** the scope of the variable the result will be put in */

View File

@@ -18,6 +18,7 @@ package org.springframework.web.servlet.tags;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
@@ -28,6 +29,8 @@ import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.support.RequestDataValueProcessor;
import org.springframework.web.util.JavaScriptUtils;
@@ -82,16 +85,20 @@ public class UrlTag extends HtmlEscapingAwareTag implements ParamAware {
private static final String URL_TYPE_ABSOLUTE = "://";
private List<Param> params;
private List<Param> params = Collections.emptyList();
private Set<String> templateParams;
private Set<String> templateParams = Collections.emptySet();
@Nullable
private UrlType type;
@Nullable
private String value;
@Nullable
private String context;
@Nullable
private String var;
private int scope = PageContext.PAGE_SCOPE;
@@ -198,9 +205,11 @@ public class UrlTag extends HtmlEscapingAwareTag implements ParamAware {
* @return the URL value as a String
* @throws JspException
*/
private String createUrl() throws JspException {
String createUrl() throws JspException {
Assert.state(this.value != null, "No value set");
HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
HttpServletResponse response = (HttpServletResponse) pageContext.getResponse();
StringBuilder url = new StringBuilder();
if (this.type == UrlType.CONTEXT_RELATIVE) {
// add application context to url
@@ -231,7 +240,7 @@ public class UrlTag extends HtmlEscapingAwareTag implements ParamAware {
// HTML and/or JavaScript escape, if demanded.
urlStr = htmlEscape(urlStr);
urlStr = this.javaScriptEscape ? JavaScriptUtils.javaScriptEscape(urlStr) : urlStr;
urlStr = (this.javaScriptEscape ? JavaScriptUtils.javaScriptEscape(urlStr) : urlStr);
return urlStr;
}

View File

@@ -30,6 +30,7 @@ import org.springframework.lang.Nullable;
*/
public abstract class AbstractUrlBasedView extends AbstractView implements InitializingBean {
@Nullable
private String url;

View File

@@ -69,10 +69,10 @@ public abstract class AbstractView extends WebApplicationObjectSupport implement
private static final int OUTPUT_BYTE_ARRAY_INITIAL_SIZE = 4096;
private String beanName;
@Nullable
private String contentType = DEFAULT_CONTENT_TYPE;
@Nullable
private String requestContextAttribute;
private final Map<String, Object> staticAttributes = new LinkedHashMap<>();
@@ -81,26 +81,12 @@ public abstract class AbstractView extends WebApplicationObjectSupport implement
private boolean exposeContextBeansAsAttributes = false;
private Set<String> exposedContextBeanNames;
/**
* Set the view's name. Helpful for traceability.
* <p>Framework code must call this when constructing views.
*/
@Override
public void setBeanName(String beanName) {
this.beanName = beanName;
}
/**
* Return the view's name. Should never be {@code null},
* if the view was correctly configured.
*/
@Nullable
public String getBeanName() {
return this.beanName;
}
private Set<String> exposedContextBeanNames;
@Nullable
private String beanName;
/**
* Set the content type for this view.
@@ -287,6 +273,24 @@ public abstract class AbstractView extends WebApplicationObjectSupport implement
this.exposedContextBeanNames = new HashSet<>(Arrays.asList(exposedContextBeanNames));
}
/**
* Set the view's name. Helpful for traceability.
* <p>Framework code must call this when constructing views.
*/
@Override
public void setBeanName(String beanName) {
this.beanName = beanName;
}
/**
* Return the view's name. Should never be {@code null},
* if the view was correctly configured.
*/
@Nullable
public String getBeanName() {
return this.beanName;
}
/**
* Prepares the view given the specified model, merging it with static

View File

@@ -88,27 +88,21 @@ import org.springframework.web.servlet.ViewResolver;
public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport
implements ViewResolver, Ordered, InitializingBean {
private int order = Ordered.HIGHEST_PRECEDENCE;
@Nullable
private ContentNegotiationManager contentNegotiationManager;
private final ContentNegotiationManagerFactoryBean cnmFactoryBean = new ContentNegotiationManagerFactoryBean();
private boolean useNotAcceptableStatusCode = false;
@Nullable
private List<View> defaultViews;
@Nullable
private List<ViewResolver> viewResolvers;
private int order = Ordered.HIGHEST_PRECEDENCE;
public void setOrder(int order) {
this.order = order;
}
@Override
public int getOrder() {
return this.order;
}
/**
* Set the {@link ContentNegotiationManager} to use to determine requested media types.
@@ -124,6 +118,7 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport
* Return the {@link ContentNegotiationManager} to use to determine requested media types.
* @since 4.1.9
*/
@Nullable
public ContentNegotiationManager getContentNegotiationManager() {
return this.contentNegotiationManager;
}
@@ -157,7 +152,8 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport
}
public List<View> getDefaultViews() {
return Collections.unmodifiableList(this.defaultViews);
return (this.defaultViews != null ? Collections.unmodifiableList(this.defaultViews) :
Collections.emptyList());
}
/**
@@ -169,7 +165,17 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport
}
public List<ViewResolver> getViewResolvers() {
return Collections.unmodifiableList(this.viewResolvers);
return (this.viewResolvers != null ? Collections.unmodifiableList(this.viewResolvers) :
Collections.emptyList());
}
public void setOrder(int order) {
this.order = order;
}
@Override
public int getOrder() {
return this.order;
}
@@ -243,6 +249,7 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport
*/
@Nullable
protected List<MediaType> getMediaTypes(HttpServletRequest request) {
Assert.state(this.contentNegotiationManager != null, "No ContentNegotiationManager set");
try {
ServletWebRequest webRequest = new ServletWebRequest(request);
@@ -297,18 +304,21 @@ public class ContentNegotiatingViewResolver extends WebApplicationObjectSupport
throws Exception {
List<View> candidateViews = new ArrayList<>();
for (ViewResolver viewResolver : this.viewResolvers) {
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
candidateViews.add(view);
}
for (MediaType requestedMediaType : requestedMediaTypes) {
List<String> extensions = this.contentNegotiationManager.resolveFileExtensions(requestedMediaType);
for (String extension : extensions) {
String viewNameWithExtension = viewName + '.' + extension;
view = viewResolver.resolveViewName(viewNameWithExtension, locale);
if (view != null) {
candidateViews.add(view);
if (this.viewResolvers != null) {
Assert.state(this.contentNegotiationManager != null, "No ContentNegotiationManager set");
for (ViewResolver viewResolver : this.viewResolvers) {
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
candidateViews.add(view);
}
for (MediaType requestedMediaType : requestedMediaTypes) {
List<String> extensions = this.contentNegotiationManager.resolveFileExtensions(requestedMediaType);
for (String extension : extensions) {
String viewNameWithExtension = viewName + '.' + extension;
view = viewResolver.resolveViewName(viewNameWithExtension, locale);
if (view != null) {
candidateViews.add(view);
}
}
}
}

View File

@@ -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.view;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
/**
@@ -50,6 +51,7 @@ public class InternalResourceViewResolver extends UrlBasedViewResolver {
private static final boolean jstlPresent = ClassUtils.isPresent(
"javax.servlet.jsp.jstl.core.Config", InternalResourceViewResolver.class.getClassLoader());
@Nullable
private Boolean alwaysInclude;

View File

@@ -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.
@@ -20,6 +20,7 @@ import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.springframework.context.MessageSource;
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.support.JstlUtils;
import org.springframework.web.servlet.support.RequestContext;
@@ -76,6 +77,7 @@ import org.springframework.web.servlet.support.RequestContext;
*/
public class JstlView extends InternalResourceView {
@Nullable
private MessageSource messageSource;

View File

@@ -94,14 +94,17 @@ public class RedirectView extends AbstractUrlBasedView implements SmartView {
private boolean exposeModelAttributes = true;
@Nullable
private String encodingScheme;
@Nullable
private HttpStatus statusCode;
private boolean expandUriTemplateVariables = true;
private boolean propagateQueryParams = false;
@Nullable
private String[] hosts;
@@ -270,6 +273,7 @@ public class RedirectView extends AbstractUrlBasedView implements SmartView {
* Return the configured application hosts.
* @since 4.3
*/
@Nullable
public String[] getHosts() {
return this.hosts;
}

View File

@@ -32,6 +32,7 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.support.PropertiesBeanDefinitionReader;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.Ordered;
import org.springframework.lang.Nullable;
import org.springframework.web.context.support.GenericWebApplicationContext;
import org.springframework.web.servlet.View;
@@ -72,17 +73,17 @@ public class ResourceBundleViewResolver extends AbstractCachingViewResolver
private ClassLoader bundleClassLoader = Thread.currentThread().getContextClassLoader();
@Nullable
private String defaultParentView;
@Nullable
private Locale[] localesToInitialize;
/* Locale -> BeanFactory */
private final Map<Locale, BeanFactory> localeCache =
new HashMap<>();
private final Map<Locale, BeanFactory> localeCache = new HashMap<>();
/* List of ResourceBundle -> BeanFactory */
private final Map<List<ResourceBundle>, ConfigurableApplicationContext> bundleCache =
new HashMap<>();
private final Map<List<ResourceBundle>, ConfigurableApplicationContext> bundleCache = new HashMap<>();
public void setOrder(int order) {

View File

@@ -102,31 +102,39 @@ public class UrlBasedViewResolver extends AbstractCachingViewResolver implements
public static final String FORWARD_URL_PREFIX = "forward:";
@Nullable
private Class<?> viewClass;
private String prefix = "";
private String suffix = "";
@Nullable
private String contentType;
private boolean redirectContextRelative = true;
private boolean redirectHttp10Compatible = true;
@Nullable
private String[] redirectHosts;
@Nullable
private String requestContextAttribute;
/** Map of static attributes, keyed by attribute name (String) */
private final Map<String, Object> staticAttributes = new HashMap<>();
@Nullable
private Boolean exposePathVariables;
@Nullable
private Boolean exposeContextBeansAsAttributes;
@Nullable
private String[] exposedContextBeanNames;
@Nullable
private String[] viewNames;
private int order = Integer.MAX_VALUE;
@@ -276,6 +284,7 @@ public class UrlBasedViewResolver extends AbstractCachingViewResolver implements
* Return the configured application hosts for redirect purposes.
* @since 4.3
*/
@Nullable
public String[] getRedirectHosts() {
return this.redirectHosts;
}
@@ -467,7 +476,10 @@ public class UrlBasedViewResolver extends AbstractCachingViewResolver implements
if (viewName.startsWith(REDIRECT_URL_PREFIX)) {
String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());
RedirectView view = new RedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible());
view.setHosts(getRedirectHosts());
String[] hosts = getRedirectHosts();
if (hosts != null) {
view.setHosts(hosts);
}
return applyLifecycleMethods(viewName, view);
}
// Check for special "forward:" prefix.

View File

@@ -29,6 +29,7 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.Ordered;
import org.springframework.core.io.Resource;
import org.springframework.lang.Nullable;
import org.springframework.web.context.support.GenericWebApplicationContext;
import org.springframework.web.servlet.View;
@@ -63,8 +64,10 @@ public class XmlViewResolver extends AbstractCachingViewResolver
private int order = Integer.MAX_VALUE; // default: same as non-Ordered
@Nullable
private Resource location;
@Nullable
private ConfigurableApplicationContext cachedFactory;

View File

@@ -42,7 +42,7 @@ public interface FreeMarkerConfig {
Configuration getConfiguration();
/**
* Returns the {@link TaglibFactory} used to enable JSP tags to be
* Return the {@link TaglibFactory} used to enable JSP tags to be
* accessed from FreeMarker templates.
*/
TaglibFactory getTaglibFactory();

View File

@@ -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.
@@ -28,7 +28,9 @@ import freemarker.template.TemplateException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.lang.Nullable;
import org.springframework.ui.freemarker.FreeMarkerConfigurationFactory;
import org.springframework.util.Assert;
import org.springframework.web.context.ServletContextAware;
/**
@@ -78,8 +80,10 @@ import org.springframework.web.context.ServletContextAware;
public class FreeMarkerConfigurer extends FreeMarkerConfigurationFactory
implements FreeMarkerConfig, InitializingBean, ResourceLoaderAware, ServletContextAware {
@Nullable
private Configuration configuration;
@Nullable
private TaglibFactory taglibFactory;
@@ -133,6 +137,7 @@ public class FreeMarkerConfigurer extends FreeMarkerConfigurationFactory
*/
@Override
public Configuration getConfiguration() {
Assert.state(this.configuration != null, "No Configuration available");
return this.configuration;
}
@@ -141,6 +146,7 @@ public class FreeMarkerConfigurer extends FreeMarkerConfigurationFactory
*/
@Override
public TaglibFactory getTaglibFactory() {
Assert.state(this.taglibFactory != null, "No TaglibFactory available");
return this.taglibFactory;
}

View File

@@ -87,12 +87,16 @@ import org.springframework.web.servlet.view.AbstractTemplateView;
*/
public class FreeMarkerView extends AbstractTemplateView {
@Nullable
private String encoding;
@Nullable
private Configuration configuration;
@Nullable
private TaglibFactory taglibFactory;
@Nullable
private ServletContextHashModel servletContextHashModel;

View File

@@ -32,6 +32,7 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.core.io.Resource;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -87,8 +88,10 @@ public class GroovyMarkupConfigurer extends TemplateConfiguration
private String resourceLoaderPath = "classpath:";
@Nullable
private MarkupTemplateEngine templateEngine;
@Nullable
private ApplicationContext applicationContext;
@@ -119,7 +122,8 @@ public class GroovyMarkupConfigurer extends TemplateConfiguration
}
public MarkupTemplateEngine getTemplateEngine() {
return templateEngine;
Assert.state(this.templateEngine != null, "No MarkupTemplateEngine set");
return this.templateEngine;
}
@Override
@@ -128,6 +132,7 @@ public class GroovyMarkupConfigurer extends TemplateConfiguration
}
protected ApplicationContext getApplicationContext() {
Assert.state(this.applicationContext != null, "No ApplicationContext set");
return this.applicationContext;
}
@@ -209,6 +214,7 @@ public class GroovyMarkupConfigurer extends TemplateConfiguration
*/
private class LocaleTemplateResolver implements TemplateResolver {
@Nullable
private ClassLoader classLoader;
@Override
@@ -218,6 +224,7 @@ public class GroovyMarkupConfigurer extends TemplateConfiguration
@Override
public URL resolveTemplate(String templatePath) throws IOException {
Assert.state(this.classLoader != null, "No template ClassLoader available");
return GroovyMarkupConfigurer.this.resolveTemplate(this.classLoader, templatePath);
}
}

View File

@@ -31,6 +31,7 @@ import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextException;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.web.servlet.view.AbstractTemplateView;
import org.springframework.web.util.NestedServletException;
@@ -50,6 +51,7 @@ import org.springframework.web.util.NestedServletException;
*/
public class GroovyMarkupView extends AbstractTemplateView {
@Nullable
private MarkupTemplateEngine engine;
@@ -99,6 +101,7 @@ public class GroovyMarkupView extends AbstractTemplateView {
@Override
public boolean checkResource(Locale locale) throws Exception {
Assert.state(this.engine != null, "No MarkupTemplateEngine set");
try {
this.engine.resolveTemplate(getUrl());
}
@@ -124,6 +127,7 @@ public class GroovyMarkupView extends AbstractTemplateView {
* for the given view URL.
*/
protected Template getTemplate(String viewUrl) throws Exception {
Assert.state(this.engine != null, "No MarkupTemplateEngine set");
try {
return this.engine.createTemplateByPath(viewUrl);
}

View File

@@ -31,6 +31,7 @@ import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.ser.FilterProvider;
import org.springframework.http.converter.json.MappingJacksonValue;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.web.servlet.view.AbstractView;
@@ -53,6 +54,7 @@ public abstract class AbstractJackson2View extends AbstractView {
private JsonEncoding encoding = JsonEncoding.UTF8;
@Nullable
private Boolean prettyPrint;
private boolean disableCaching = true;
@@ -61,7 +63,8 @@ public abstract class AbstractJackson2View extends AbstractView {
protected AbstractJackson2View(ObjectMapper objectMapper, String contentType) {
setObjectMapper(objectMapper);
this.objectMapper = objectMapper;
configurePrettyPrint();
setContentType(contentType);
setExposePathVariables(false);
}
@@ -74,7 +77,6 @@ public abstract class AbstractJackson2View extends AbstractView {
* on the types to be serialized, in which case a custom-configured ObjectMapper is unnecessary.
*/
public void setObjectMapper(ObjectMapper objectMapper) {
Assert.notNull(objectMapper, "'objectMapper' must not be null");
this.objectMapper = objectMapper;
configurePrettyPrint();
}
@@ -184,8 +186,12 @@ public abstract class AbstractJackson2View extends AbstractView {
FilterProvider filters = (FilterProvider) model.get(FilterProvider.class.getName());
if (serializationView != null || filters != null) {
MappingJacksonValue container = new MappingJacksonValue(value);
container.setSerializationView(serializationView);
container.setFilters(filters);
if (serializationView != null) {
container.setSerializationView(serializationView);
}
if (filters != null) {
container.setFilters(filters);
}
value = container;
}
return value;

View File

@@ -78,12 +78,15 @@ public class MappingJackson2JsonView extends AbstractJackson2View {
private static final Pattern CALLBACK_PARAM_PATTERN = Pattern.compile("[0-9A-Za-z_\\.]*");
@Nullable
private String jsonPrefix;
@Nullable
private Set<String> modelKeys;
private boolean extractValueFromSingleKeyModel = false;
@Nullable
private Set<String> jsonpParameterNames = new LinkedHashSet<>(Arrays.asList("jsonp", "callback"));
@@ -146,6 +149,7 @@ public class MappingJackson2JsonView extends AbstractJackson2View {
/**
* Return the attributes in the model that should be rendered by this view.
*/
@Nullable
public final Set<String> getModelKeys() {
return this.modelKeys;
}

View File

@@ -41,7 +41,6 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextException;
import org.springframework.core.NamedThreadLocal;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.lang.Nullable;
import org.springframework.scripting.support.StandardScriptEvalException;
import org.springframework.scripting.support.StandardScriptUtils;
@@ -83,24 +82,31 @@ public class ScriptTemplateView extends AbstractUrlBasedView {
new NamedThreadLocal<>("ScriptTemplateView engines");
@Nullable
private ScriptEngine engine;
@Nullable
private String engineName;
@Nullable
private Boolean sharedEngine;
@Nullable
private String[] scripts;
@Nullable
private String renderObject;
@Nullable
private String renderFunction;
@Nullable
private Charset charset;
@Nullable
private String[] resourceLoaderPaths;
private ResourceLoader resourceLoader;
@Nullable
private volatile ScriptEngineManager scriptEngineManager;
@@ -164,15 +170,6 @@ public class ScriptTemplateView extends AbstractUrlBasedView {
this.renderFunction = functionName;
}
/**
* See {@link ScriptTemplateConfigurer#setContentType(String)}} documentation.
* @since 4.2.1
*/
@Override
public void setContentType(@Nullable String contentType) {
super.setContentType(contentType);
}
/**
* See {@link ScriptTemplateConfigurer#setCharset(Charset)} documentation.
*/
@@ -227,9 +224,6 @@ public class ScriptTemplateView extends AbstractUrlBasedView {
String resourceLoaderPath = viewConfig.getResourceLoaderPath();
setResourceLoaderPath(resourceLoaderPath == null ? DEFAULT_RESOURCE_LOADER_PATH : resourceLoaderPath);
}
if (this.resourceLoader == null) {
this.resourceLoader = getApplicationContext();
}
if (this.sharedEngine == null && viewConfig.isSharedEngine() != null) {
this.sharedEngine = viewConfig.isSharedEngine();
}
@@ -248,11 +242,12 @@ public class ScriptTemplateView extends AbstractUrlBasedView {
loadScripts(this.engine);
}
else {
setEngine(createEngineFromName());
setEngine(createEngineFromName(this.engineName));
}
if (this.renderFunction != null && this.engine != null) {
Assert.isInstanceOf(Invocable.class, this.engine, "ScriptEngine must implement Invocable when 'renderFunction' is specified.");
Assert.isInstanceOf(Invocable.class, this.engine,
"ScriptEngine must implement Invocable when 'renderFunction' is specified");
}
}
@@ -263,27 +258,31 @@ public class ScriptTemplateView extends AbstractUrlBasedView {
engines = new HashMap<>(4);
enginesHolder.set(engines);
}
Assert.state(this.engineName != null, "No engine name specified");
Object engineKey = (!ObjectUtils.isEmpty(this.scripts) ?
new EngineKey(this.engineName, this.scripts) : this.engineName);
ScriptEngine engine = engines.get(engineKey);
if (engine == null) {
engine = createEngineFromName();
engine = createEngineFromName(engineName);
engines.put(engineKey, engine);
}
return engine;
}
else {
// Simply return the configured ScriptEngine...
Assert.state(this.engine != null, "No shared engine available");
return this.engine;
}
}
protected ScriptEngine createEngineFromName() {
if (this.scriptEngineManager == null) {
this.scriptEngineManager = new ScriptEngineManager(obtainApplicationContext().getClassLoader());
protected ScriptEngine createEngineFromName(String engineName) {
ScriptEngineManager scriptEngineManager = this.scriptEngineManager;
if (scriptEngineManager == null) {
scriptEngineManager = new ScriptEngineManager(obtainApplicationContext().getClassLoader());
this.scriptEngineManager = scriptEngineManager;
}
ScriptEngine engine = StandardScriptUtils.retrieveEngineByName(this.scriptEngineManager, this.engineName);
ScriptEngine engine = StandardScriptUtils.retrieveEngineByName(scriptEngineManager, engineName);
loadScripts(engine);
return engine;
}
@@ -307,10 +306,12 @@ public class ScriptTemplateView extends AbstractUrlBasedView {
@Nullable
protected Resource getResource(String location) {
for (String path : this.resourceLoaderPaths) {
Resource resource = this.resourceLoader.getResource(path + location);
if (resource.exists()) {
return resource;
if (this.resourceLoaderPaths != null) {
for (String path : this.resourceLoaderPaths) {
Resource resource = obtainApplicationContext().getResource(path + location);
if (resource.exists()) {
return resource;
}
}
}
return null;
@@ -341,7 +342,9 @@ public class ScriptTemplateView extends AbstractUrlBasedView {
super.prepareResponse(request, response);
setResponseContentType(request, response);
response.setCharacterEncoding(this.charset.name());
if (this.charset != null) {
response.setCharacterEncoding(this.charset.name());
}
}
@Override
@@ -375,10 +378,10 @@ public class ScriptTemplateView extends AbstractUrlBasedView {
}
else if (this.renderObject != null) {
Object thiz = engine.eval(this.renderObject);
html = ((Invocable)engine).invokeMethod(thiz, this.renderFunction, template, model, context);
html = ((Invocable) engine).invokeMethod(thiz, this.renderFunction, template, model, context);
}
else {
html = ((Invocable)engine).invokeFunction(this.renderFunction, template, model, context);
html = ((Invocable) engine).invokeFunction(this.renderFunction, template, model, context);
}
response.getWriter().write(String.valueOf(html));
@@ -393,7 +396,9 @@ public class ScriptTemplateView extends AbstractUrlBasedView {
if (resource == null) {
throw new IllegalStateException("Template resource [" + path + "] not found");
}
InputStreamReader reader = new InputStreamReader(resource.getInputStream(), this.charset);
InputStreamReader reader = (this.charset != null ?
new InputStreamReader(resource.getInputStream(), this.charset) :
new InputStreamReader(resource.getInputStream()));
return FileCopyUtils.copyToString(reader);
}

View File

@@ -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,6 +63,8 @@ import org.springframework.beans.BeanWrapper;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.web.context.ServletContextAware;
@@ -130,20 +132,25 @@ public class TilesConfigurer implements ServletContextAware, InitializingBean, D
protected final Log logger = LogFactory.getLog(getClass());
@Nullable
private TilesInitializer tilesInitializer;
@Nullable
private String[] definitions;
private boolean checkRefresh = false;
private boolean validateDefinitions = true;
@Nullable
private Class<? extends DefinitionsFactory> definitionsFactoryClass;
@Nullable
private Class<? extends PreparerFactory> preparerFactoryClass;
private boolean useMutableTilesContainer = false;
@Nullable
private ServletContext servletContext;
@@ -264,6 +271,7 @@ public class TilesConfigurer implements ServletContextAware, InitializingBean, D
*/
@Override
public void afterPropertiesSet() throws TilesException {
Assert.state(this.servletContext != null, "No ServletContext available");
ApplicationContext preliminaryContext = new SpringWildcardServletTilesApplicationContext(this.servletContext);
if (this.tilesInitializer == null) {
this.tilesInitializer = new SpringTilesInitializer();
@@ -277,7 +285,9 @@ public class TilesConfigurer implements ServletContextAware, InitializingBean, D
*/
@Override
public void destroy() throws TilesException {
this.tilesInitializer.destroy();
if (this.tilesInitializer != null) {
this.tilesInitializer.destroy();
}
}

View File

@@ -32,6 +32,7 @@ import org.apache.tiles.request.render.Renderer;
import org.apache.tiles.request.servlet.ServletRequest;
import org.apache.tiles.request.servlet.ServletUtil;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
@@ -54,12 +55,14 @@ import org.springframework.web.servlet.view.AbstractUrlBasedView;
*/
public class TilesView extends AbstractUrlBasedView {
@Nullable
private Renderer renderer;
private boolean exposeJstlAttributes = true;
private boolean alwaysInclude = false;
@Nullable
private ApplicationContext applicationContext;
@@ -107,17 +110,21 @@ public class TilesView extends AbstractUrlBasedView {
@Override
public boolean checkResource(final Locale locale) throws Exception {
Assert.state(this.renderer != null, "No Renderer set");
HttpServletRequest servletRequest = null;
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (requestAttributes instanceof ServletRequestAttributes) {
servletRequest = ((ServletRequestAttributes) requestAttributes).getRequest();
}
Request request = new ServletRequest(this.applicationContext, servletRequest, null) {
@Override
public Locale getRequestLocale() {
return locale;
}
};
return this.renderer.isRenderable(getUrl(), request);
}
@@ -125,6 +132,8 @@ public class TilesView extends AbstractUrlBasedView {
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,
HttpServletResponse response) throws Exception {
Assert.state(this.renderer != null, "No Renderer set");
exposeModelAsRequestAttributes(model, request);
if (this.exposeJstlAttributes) {
JstlUtils.exposeLocalizationContext(new RequestContext(request, getServletContext()));

View File

@@ -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.
@@ -18,6 +18,7 @@ package org.springframework.web.servlet.view.tiles3;
import org.apache.tiles.request.render.Renderer;
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.view.UrlBasedViewResolver;
/**
@@ -32,8 +33,10 @@ import org.springframework.web.servlet.view.UrlBasedViewResolver;
*/
public class TilesViewResolver extends UrlBasedViewResolver {
@Nullable
private Renderer renderer;
@Nullable
private Boolean alwaysInclude;

View File

@@ -22,6 +22,7 @@ import com.fasterxml.jackson.annotation.JsonView;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.validation.BindingResult;
import org.springframework.web.servlet.View;
@@ -47,6 +48,7 @@ public class MappingJackson2XmlView extends AbstractJackson2View {
public static final String DEFAULT_CONTENT_TYPE = "application/xml";
@Nullable
private String modelKey;

View File

@@ -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.
@@ -18,7 +18,6 @@ package org.springframework.web.servlet.view.xml;
import java.io.ByteArrayOutputStream;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.JAXBElement;
@@ -52,8 +51,10 @@ public class MarshallingView extends AbstractView {
public static final String DEFAULT_CONTENT_TYPE = "application/xml";
@Nullable
private Marshaller marshaller;
@Nullable
private String modelKey;
@@ -106,6 +107,8 @@ public class MarshallingView extends AbstractView {
if (toBeMarshalled == null) {
throw new IllegalStateException("Unable to locate object to be marshalled in model: " + model);
}
Assert.state(this.marshaller != null, "No Marshaller set");
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
this.marshaller.marshal(toBeMarshalled, new StreamResult(baos));
@@ -159,6 +162,7 @@ public class MarshallingView extends AbstractView {
* @see Marshaller#supports(Class)
*/
protected boolean isEligibleForMarshalling(String modelKey, Object value) {
Assert.state(this.marshaller != null, "No Marshaller set");
Class<?> classToCheck = value.getClass();
if (value instanceof JAXBElement) {
classToCheck = ((JAXBElement) value).getDeclaredType();

View File

@@ -75,22 +75,28 @@ import org.springframework.web.util.WebUtils;
*/
public class XsltView extends AbstractUrlBasedView {
@Nullable
private Class<? extends TransformerFactory> transformerFactoryClass;
@Nullable
private String sourceKey;
@Nullable
private URIResolver uriResolver;
private ErrorListener errorListener = new SimpleTransformErrorListener(logger);
private boolean indent = true;
@Nullable
private Properties outputProperties;
private boolean cacheTemplates = true;
@Nullable
private TransformerFactory transformerFactory;
@Nullable
private Templates cachedTemplates;
@@ -215,6 +221,7 @@ public class XsltView extends AbstractUrlBasedView {
* @return the TransformerFactory (never {@code null})
*/
protected final TransformerFactory getTransformerFactory() {
Assert.state(this.transformerFactory != null, "No TransformerFactory available");
return this.transformerFactory;
}
@@ -416,7 +423,7 @@ public class XsltView extends AbstractUrlBasedView {
private Templates loadTemplates() throws ApplicationContextException {
Source stylesheetSource = getStylesheetSource();
try {
Templates templates = this.transformerFactory.newTemplates(stylesheetSource);
Templates templates = getTransformerFactory().newTemplates(stylesheetSource);
if (logger.isDebugEnabled()) {
logger.debug("Loading templates '" + templates + "'");
}

View File

@@ -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,6 +20,7 @@ import java.util.Properties;
import javax.xml.transform.ErrorListener;
import javax.xml.transform.URIResolver;
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.view.AbstractUrlBasedView;
import org.springframework.web.servlet.view.UrlBasedViewResolver;
@@ -34,14 +35,18 @@ import org.springframework.web.servlet.view.UrlBasedViewResolver;
*/
public class XsltViewResolver extends UrlBasedViewResolver {
@Nullable
private String sourceKey;
@Nullable
private URIResolver uriResolver;
@Nullable
private ErrorListener errorListener;
private boolean indent = true;
@Nullable
private Properties outputProperties;
private boolean cacheTemplates = true;
@@ -124,7 +129,9 @@ public class XsltViewResolver extends UrlBasedViewResolver {
@Override
protected AbstractUrlBasedView buildView(String viewName) throws Exception {
XsltView view = (XsltView) super.buildView(viewName);
view.setSourceKey(this.sourceKey);
if (this.sourceKey != null) {
view.setSourceKey(this.sourceKey);
}
if (this.uriResolver != null) {
view.setUriResolver(this.uriResolver);
}
@@ -132,7 +139,9 @@ public class XsltViewResolver extends UrlBasedViewResolver {
view.setErrorListener(this.errorListener);
}
view.setIndent(this.indent);
view.setOutputProperties(this.outputProperties);
if (this.outputProperties != null) {
view.setOutputProperties(this.outputProperties);
}
view.setCacheTemplates(this.cacheTemplates);
return view;
}