SPR-8352 Init and apply MappedInterceptors from AbstractHandlerMapping

This commit is contained in:
Rossen Stoyanchev 2011-05-19 16:45:25 +00:00
parent 60aa598c03
commit 0bf92782ea
11 changed files with 298 additions and 341 deletions

View File

@ -18,6 +18,7 @@ Changes in version 3.1 M2 (2011-??-??)
* support for URI template variables in view names with the "redirect:" prefix * support for URI template variables in view names with the "redirect:" prefix
* a flag for extracting the value from single-key models in MappingJacksonJsonView * a flag for extracting the value from single-key models in MappingJacksonJsonView
* allow bean references in mvc:interceptor namespace elements * allow bean references in mvc:interceptor namespace elements
* consolidated the initialization and use of MappedInterceptors in AbstractHandlerMapping
Changes in version 3.1 M1 (2011-02-11) Changes in version 3.1 M1 (2011-02-11)
-------------------------------------- --------------------------------------

View File

@ -118,8 +118,8 @@ public class InterceptorConfigurer {
/** /**
* Returns all registered interceptors. * Returns all registered interceptors.
*/ */
protected MappedInterceptor[] getInterceptors() { protected List<MappedInterceptor> getInterceptors() {
return mappedInterceptors.toArray(new MappedInterceptor[mappedInterceptors.size()]); return mappedInterceptors;
} }
} }

View File

@ -124,8 +124,15 @@ class WebMvcConfiguration implements ApplicationContextAware, ServletContextAwar
private ApplicationContext applicationContext; private ApplicationContext applicationContext;
private List<MappedInterceptor> mappedInterceptors;
private List<HttpMessageConverter<?>> messageConverters;
@Autowired(required = false) @Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) { public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (configurers == null || configurers.isEmpty()) {
return;
}
this.configurers.addWebMvcConfigurers(configurers); this.configurers.addWebMvcConfigurers(configurers);
} }
@ -140,17 +147,19 @@ class WebMvcConfiguration implements ApplicationContextAware, ServletContextAwar
@Bean @Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() { public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping mapping = new RequestMappingHandlerMapping(); RequestMappingHandlerMapping mapping = new RequestMappingHandlerMapping();
mapping.setMappedInterceptors(getMappedInterceptors()); mapping.setInterceptors(getMappedInterceptors());
mapping.setOrder(0); mapping.setOrder(0);
return mapping; return mapping;
} }
private MappedInterceptor[] getMappedInterceptors() { private Object[] getMappedInterceptors() {
// TODO : prepare and store in instance var ? if (mappedInterceptors == null) {
InterceptorConfigurer configurer = new InterceptorConfigurer(); InterceptorConfigurer configurer = new InterceptorConfigurer();
configurers.configureInterceptors(configurer); configurers.configureInterceptors(configurer);
configurer.addInterceptor(new ConversionServiceExposingInterceptor(conversionService())); configurer.addInterceptor(new ConversionServiceExposingInterceptor(conversionService()));
return configurer.getInterceptors(); mappedInterceptors = configurer.getInterceptors();
}
return mappedInterceptors.toArray();
} }
@Bean @Bean
@ -160,7 +169,7 @@ class WebMvcConfiguration implements ApplicationContextAware, ServletContextAwar
configurers.configureViewControllers(configurer); configurers.configureViewControllers(configurer);
SimpleUrlHandlerMapping handlerMapping = configurer.getHandlerMapping(); SimpleUrlHandlerMapping handlerMapping = configurer.getHandlerMapping();
handlerMapping.setMappedInterceptors(getMappedInterceptors()); handlerMapping.setInterceptors(getMappedInterceptors());
return handlerMapping; return handlerMapping;
} }
@ -168,7 +177,7 @@ class WebMvcConfiguration implements ApplicationContextAware, ServletContextAwar
public BeanNameUrlHandlerMapping beanNameHandlerMapping() { public BeanNameUrlHandlerMapping beanNameHandlerMapping() {
BeanNameUrlHandlerMapping mapping = new BeanNameUrlHandlerMapping(); BeanNameUrlHandlerMapping mapping = new BeanNameUrlHandlerMapping();
mapping.setOrder(2); mapping.setOrder(2);
mapping.setMappedInterceptors(getMappedInterceptors()); mapping.setInterceptors(getMappedInterceptors());
return mapping; return mapping;
} }
@ -190,6 +199,7 @@ class WebMvcConfiguration implements ApplicationContextAware, ServletContextAwar
@Bean @Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() { public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
RequestMappingHandlerAdapter adapter = new RequestMappingHandlerAdapter(); RequestMappingHandlerAdapter adapter = new RequestMappingHandlerAdapter();
adapter.setMessageConverters(getMessageConverters());
ConfigurableWebBindingInitializer bindingInitializer = new ConfigurableWebBindingInitializer(); ConfigurableWebBindingInitializer bindingInitializer = new ConfigurableWebBindingInitializer();
bindingInitializer.setConversionService(conversionService()); bindingInitializer.setConversionService(conversionService());
@ -204,24 +214,28 @@ class WebMvcConfiguration implements ApplicationContextAware, ServletContextAwar
configurers.addReturnValueHandlers(returnValueHandlers); configurers.addReturnValueHandlers(returnValueHandlers);
adapter.setCustomReturnValueHandlers(returnValueHandlers); adapter.setCustomReturnValueHandlers(returnValueHandlers);
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
configurers.configureMessageConverters(converters);
if (converters.size() == 0) {
addDefaultHttpMessageConverters(converters);
}
adapter.setMessageConverters(converters);
return adapter; return adapter;
} }
@Bean(name="mvcConversionService") private List<HttpMessageConverter<?>> getMessageConverters() {
if (messageConverters == null) {
messageConverters = new ArrayList<HttpMessageConverter<?>>();
configurers.configureMessageConverters(messageConverters);
if (messageConverters.isEmpty()) {
addDefaultHttpMessageConverters(messageConverters);
}
}
return messageConverters;
}
@Bean(name="webMvcConversionService")
public FormattingConversionService conversionService() { public FormattingConversionService conversionService() {
FormattingConversionService conversionService = new DefaultFormattingConversionService(); FormattingConversionService conversionService = new DefaultFormattingConversionService();
configurers.addFormatters(conversionService); configurers.addFormatters(conversionService);
return conversionService; return conversionService;
} }
@Bean(name="mvcValidator") @Bean(name="webMvcValidator")
public Validator validator() { public Validator validator() {
Validator validator = configurers.getValidator(); Validator validator = configurers.getValidator();
if (validator != null) { if (validator != null) {
@ -240,37 +254,30 @@ class WebMvcConfiguration implements ApplicationContextAware, ServletContextAwar
return (Validator) BeanUtils.instantiate(clazz); return (Validator) BeanUtils.instantiate(clazz);
} }
else { else {
return new Validator() { return NOOP_VALIDATOR;
public void validate(Object target, Errors errors) {
}
public boolean supports(Class<?> clazz) {
return false;
}
};
} }
} }
private void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> converters) { private void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
StringHttpMessageConverter stringConverter = new StringHttpMessageConverter(); StringHttpMessageConverter stringConverter = new StringHttpMessageConverter();
stringConverter.setWriteAcceptCharset(false); stringConverter.setWriteAcceptCharset(false);
converters.add(new ByteArrayHttpMessageConverter()); messageConverters.add(new ByteArrayHttpMessageConverter());
converters.add(stringConverter); messageConverters.add(stringConverter);
converters.add(new ResourceHttpMessageConverter()); messageConverters.add(new ResourceHttpMessageConverter());
converters.add(new SourceHttpMessageConverter<Source>()); messageConverters.add(new SourceHttpMessageConverter<Source>());
converters.add(new XmlAwareFormHttpMessageConverter()); messageConverters.add(new XmlAwareFormHttpMessageConverter());
ClassLoader classLoader = getClass().getClassLoader(); ClassLoader classLoader = getClass().getClassLoader();
if (ClassUtils.isPresent("javax.xml.bind.Binder", classLoader)) { if (ClassUtils.isPresent("javax.xml.bind.Binder", classLoader)) {
converters.add(new Jaxb2RootElementHttpMessageConverter()); messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
} }
if (ClassUtils.isPresent("org.codehaus.jackson.map.ObjectMapper", classLoader)) { if (ClassUtils.isPresent("org.codehaus.jackson.map.ObjectMapper", classLoader)) {
converters.add(new MappingJacksonHttpMessageConverter()); messageConverters.add(new MappingJacksonHttpMessageConverter());
} }
if (ClassUtils.isPresent("com.sun.syndication.feed.WireFeed", classLoader)) { if (ClassUtils.isPresent("com.sun.syndication.feed.WireFeed", classLoader)) {
converters.add(new AtomFeedHttpMessageConverter()); messageConverters.add(new AtomFeedHttpMessageConverter());
converters.add(new RssChannelHttpMessageConverter()); messageConverters.add(new RssChannelHttpMessageConverter());
} }
} }
@ -303,16 +310,19 @@ class WebMvcConfiguration implements ApplicationContextAware, ServletContextAwar
private HandlerExceptionResolver createExceptionHandlerExceptionResolver() throws Exception { private HandlerExceptionResolver createExceptionHandlerExceptionResolver() throws Exception {
ExceptionHandlerExceptionResolver resolver = new ExceptionHandlerExceptionResolver(); ExceptionHandlerExceptionResolver resolver = new ExceptionHandlerExceptionResolver();
resolver.setMessageConverters(getMessageConverters());
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
configurers.configureMessageConverters(converters);
if (converters.size() == 0) {
addDefaultHttpMessageConverters(converters);
}
resolver.setMessageConverters(converters);
resolver.afterPropertiesSet(); resolver.afterPropertiesSet();
return resolver; return resolver;
} }
private static final Validator NOOP_VALIDATOR = new Validator() {
public boolean supports(Class<?> clazz) {
return false;
}
public void validate(Object target, Errors errors) {
}
};
} }

View File

@ -19,28 +19,39 @@ package org.springframework.web.servlet.handler;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.Assert;
import org.springframework.util.PathMatcher;
import org.springframework.web.context.request.WebRequestInterceptor; import org.springframework.web.context.request.WebRequestInterceptor;
import org.springframework.web.context.support.WebApplicationObjectSupport; import org.springframework.web.context.support.WebApplicationObjectSupport;
import org.springframework.web.servlet.HandlerExecutionChain; import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.HandlerMapping; import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.util.UrlPathHelper;
/** /**
* Abstract base class for {@link org.springframework.web.servlet.HandlerMapping} * Abstract base class for {@link org.springframework.web.servlet.HandlerMapping}
* implementations. Supports ordering, a default handler, and handler interceptors. * implementations. Supports ordering, a default handler, handler interceptors,
* including handler interceptors mapped by path patterns.
* *
* <p>Note: This base class does <i>not</i> support exposure of the * <p>Note: This base class does <i>not</i> support exposure of the
* {@link #PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE}. Support for this attribute * {@link #PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE}. Support for this attribute
* is up to concrete subclasses, typically based on request URL mappings. * is up to concrete subclasses, typically based on request URL mappings.
* *
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Rossen Stoyanchev
* @since 07.04.2003 * @since 07.04.2003
* @see #getHandlerInternal * @see #getHandlerInternal
* @see #setDefaultHandler * @see #setDefaultHandler
* @see #setAlwaysUseFullPath
* @see #setUrlDecode
* @see org.springframework.util.AntPathMatcher
* @see #setInterceptors * @see #setInterceptors
* @see org.springframework.web.servlet.HandlerInterceptor * @see org.springframework.web.servlet.HandlerInterceptor
*/ */
@ -51,10 +62,15 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
private Object defaultHandler; private Object defaultHandler;
private UrlPathHelper urlPathHelper = new UrlPathHelper();
private PathMatcher pathMatcher = new AntPathMatcher();
private final List<Object> interceptors = new ArrayList<Object>(); private final List<Object> interceptors = new ArrayList<Object>();
private HandlerInterceptor[] adaptedInterceptors; private final List<HandlerInterceptor> adaptedInterceptors = new ArrayList<HandlerInterceptor>();
private final List<MappedInterceptor> mappedInterceptors = new ArrayList<MappedInterceptor>();
/** /**
* Specify the order value for this HandlerMapping bean. * Specify the order value for this HandlerMapping bean.
@ -86,9 +102,69 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
return this.defaultHandler; return this.defaultHandler;
} }
/**
* Set if URL lookup should always use the full path within the current servlet
* context. Else, the path within the current servlet mapping is used if applicable
* (that is, in the case of a ".../*" servlet mapping in web.xml).
* <p>Default is "false".
* @see org.springframework.web.util.UrlPathHelper#setAlwaysUseFullPath
*/
public void setAlwaysUseFullPath(boolean alwaysUseFullPath) {
this.urlPathHelper.setAlwaysUseFullPath(alwaysUseFullPath);
}
/**
* Set if context path and request URI should be URL-decoded. Both are returned
* <i>undecoded</i> by the Servlet API, in contrast to the servlet path.
* <p>Uses either the request encoding or the default encoding according
* to the Servlet spec (ISO-8859-1).
* @see org.springframework.web.util.UrlPathHelper#setUrlDecode
*/
public void setUrlDecode(boolean urlDecode) {
this.urlPathHelper.setUrlDecode(urlDecode);
}
/**
* Set the UrlPathHelper to use for resolution of lookup paths.
* <p>Use this to override the default UrlPathHelper with a custom subclass,
* or to share common UrlPathHelper settings across multiple HandlerMappings
* and MethodNameResolvers.
*/
public void setUrlPathHelper(UrlPathHelper urlPathHelper) {
Assert.notNull(urlPathHelper, "UrlPathHelper must not be null");
this.urlPathHelper = urlPathHelper;
}
/**
* Return the UrlPathHelper implementation to use for resolution of lookup paths.
*/
public UrlPathHelper getUrlPathHelper() {
return urlPathHelper;
}
/**
* Set the PathMatcher implementation to use for matching URL paths
* against registered URL patterns. Default is AntPathMatcher.
* @see org.springframework.util.AntPathMatcher
*/
public void setPathMatcher(PathMatcher pathMatcher) {
Assert.notNull(pathMatcher, "PathMatcher must not be null");
this.pathMatcher = pathMatcher;
}
/**
* Return the PathMatcher implementation to use for matching URL paths
* against registered URL patterns.
*/
public PathMatcher getPathMatcher() {
return this.pathMatcher;
}
/** /**
* Set the interceptors to apply for all handlers mapped by this handler mapping. * Set the interceptors to apply for all handlers mapped by this handler mapping.
* <p>Supported interceptor types are HandlerInterceptor and WebRequestInterceptor. * <p>Supported interceptor types are HandlerInterceptor, WebRequestInterceptor, and MappedInterceptor.
* Mapped interceptors apply only to request URLs that match its path patterns.
* Mapped interceptor beans are also detected by type during initialization.
* @param interceptors array of handler interceptors, or <code>null</code> if none * @param interceptors array of handler interceptors, or <code>null</code> if none
* @see #adaptInterceptor * @see #adaptInterceptor
* @see org.springframework.web.servlet.HandlerInterceptor * @see org.springframework.web.servlet.HandlerInterceptor
@ -107,6 +183,7 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
@Override @Override
protected void initApplicationContext() throws BeansException { protected void initApplicationContext() throws BeansException {
extendInterceptors(this.interceptors); extendInterceptors(this.interceptors);
detectMappedInterceptors(this.mappedInterceptors);
initInterceptors(); initInterceptors();
} }
@ -124,19 +201,37 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
} }
/** /**
* Initialize the specified interceptors, adapting them where necessary. * Detects beans of type {@link MappedInterceptor} and adds them to the list of mapped interceptors.
* This is done in addition to any {@link MappedInterceptor}s that may have been provided via
* {@link #setInterceptors(Object[])}. Subclasses can override this method to change that.
*
* @param mappedInterceptors an empty list to add MappedInterceptor types to
*/
protected void detectMappedInterceptors(List<MappedInterceptor> mappedInterceptors) {
mappedInterceptors.addAll(
BeanFactoryUtils.beansOfTypeIncludingAncestors(
getApplicationContext(),MappedInterceptor.class, true, false).values());
}
/**
* Initialize the specified interceptors, checking for {@link MappedInterceptor}s and adapting
* HandlerInterceptors where necessary.
* @see #setInterceptors * @see #setInterceptors
* @see #adaptInterceptor * @see #adaptInterceptor
*/ */
protected void initInterceptors() { protected void initInterceptors() {
if (!this.interceptors.isEmpty()) { if (!this.interceptors.isEmpty()) {
this.adaptedInterceptors = new HandlerInterceptor[this.interceptors.size()];
for (int i = 0; i < this.interceptors.size(); i++) { for (int i = 0; i < this.interceptors.size(); i++) {
Object interceptor = this.interceptors.get(i); Object interceptor = this.interceptors.get(i);
if (interceptor == null) { if (interceptor == null) {
throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null"); throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null");
} }
this.adaptedInterceptors[i] = adaptInterceptor(interceptor); if (interceptor instanceof MappedInterceptor) {
mappedInterceptors.add((MappedInterceptor) interceptor);
}
else {
adaptedInterceptors.add(adaptInterceptor(interceptor));
}
} }
} }
} }
@ -169,9 +264,18 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
* @return the array of HandlerInterceptors, or <code>null</code> if none * @return the array of HandlerInterceptors, or <code>null</code> if none
*/ */
protected final HandlerInterceptor[] getAdaptedInterceptors() { protected final HandlerInterceptor[] getAdaptedInterceptors() {
return this.adaptedInterceptors; int count = adaptedInterceptors.size();
return (count > 0) ? adaptedInterceptors.toArray(new HandlerInterceptor[count]) : null;
} }
/**
* Return all configured {@link MappedInterceptor}s as an array.
* @return the array of {@link MappedInterceptor}s, or <code>null</code> if none
*/
protected final MappedInterceptor[] getMappedInterceptors() {
int count = mappedInterceptors.size();
return (count > 0) ? mappedInterceptors.toArray(new MappedInterceptor[count]) : null;
}
/** /**
* Look up a handler for the given request, falling back to the default * Look up a handler for the given request, falling back to the default
@ -212,7 +316,8 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
/** /**
* Build a HandlerExecutionChain for the given handler, including applicable interceptors. * Build a HandlerExecutionChain for the given handler, including applicable interceptors.
* <p>The default implementation simply builds a standard HandlerExecutionChain with * <p>The default implementation simply builds a standard HandlerExecutionChain with
* the given handler and this handler mapping's common interceptors. Subclasses may * the given handler, the handler mapping's common interceptors, and any {@link MappedInterceptor}s
* matching to the current request URL. Subclasses may
* override this in order to extend/rearrange the list of interceptors. * override this in order to extend/rearrange the list of interceptors.
* <p><b>NOTE:</b> The passed-in handler object may be a raw handler or a pre-built * <p><b>NOTE:</b> The passed-in handler object may be a raw handler or a pre-built
* HandlerExecutionChain. This method should handle those two cases explicitly, * HandlerExecutionChain. This method should handle those two cases explicitly,
@ -225,14 +330,20 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
* @see #getAdaptedInterceptors() * @see #getAdaptedInterceptors()
*/ */
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) { protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
if (handler instanceof HandlerExecutionChain) { HandlerExecutionChain chain =
HandlerExecutionChain chain = (HandlerExecutionChain) handler; (handler instanceof HandlerExecutionChain) ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler);
chain.addInterceptors(getAdaptedInterceptors()); chain.addInterceptors(getAdaptedInterceptors());
return chain;
} String lookupPath = urlPathHelper.getLookupPathForRequest(request);
else { for (MappedInterceptor mappedInterceptor : mappedInterceptors) {
return new HandlerExecutionChain(handler, getAdaptedInterceptors()); if (mappedInterceptor.matches(lookupPath, pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
} }
} }
return chain;
}
} }

View File

@ -27,14 +27,10 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.util.PathMatcher;
import org.springframework.web.servlet.HandlerExecutionChain; import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.HandlerMapping; import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.util.UrlPathHelper;
/** /**
* Abstract base class for URL-mapped {@link org.springframework.web.servlet.HandlerMapping} * Abstract base class for URL-mapped {@link org.springframework.web.servlet.HandlerMapping}
@ -54,76 +50,15 @@ import org.springframework.web.util.UrlPathHelper;
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Arjen Poutsma * @author Arjen Poutsma
* @since 16.04.2003 * @since 16.04.2003
* @see #setAlwaysUseFullPath
* @see #setUrlDecode
* @see org.springframework.util.AntPathMatcher
*/ */
public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping { public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
private UrlPathHelper urlPathHelper = new UrlPathHelper();
private PathMatcher pathMatcher = new AntPathMatcher();
private Object rootHandler; private Object rootHandler;
private boolean lazyInitHandlers = false; private boolean lazyInitHandlers = false;
private final Map<String, Object> handlerMap = new LinkedHashMap<String, Object>(); private final Map<String, Object> handlerMap = new LinkedHashMap<String, Object>();
private MappedInterceptors mappedInterceptors;
/**
* Set if URL lookup should always use the full path within the current servlet
* context. Else, the path within the current servlet mapping is used if applicable
* (that is, in the case of a ".../*" servlet mapping in web.xml).
* <p>Default is "false".
* @see org.springframework.web.util.UrlPathHelper#setAlwaysUseFullPath
*/
public void setAlwaysUseFullPath(boolean alwaysUseFullPath) {
this.urlPathHelper.setAlwaysUseFullPath(alwaysUseFullPath);
}
/**
* Set if context path and request URI should be URL-decoded. Both are returned
* <i>undecoded</i> by the Servlet API, in contrast to the servlet path.
* <p>Uses either the request encoding or the default encoding according
* to the Servlet spec (ISO-8859-1).
* @see org.springframework.web.util.UrlPathHelper#setUrlDecode
*/
public void setUrlDecode(boolean urlDecode) {
this.urlPathHelper.setUrlDecode(urlDecode);
}
/**
* Set the UrlPathHelper to use for resolution of lookup paths.
* <p>Use this to override the default UrlPathHelper with a custom subclass,
* or to share common UrlPathHelper settings across multiple HandlerMappings
* and MethodNameResolvers.
* @see org.springframework.web.servlet.mvc.multiaction.AbstractUrlMethodNameResolver#setUrlPathHelper
*/
public void setUrlPathHelper(UrlPathHelper urlPathHelper) {
Assert.notNull(urlPathHelper, "UrlPathHelper must not be null");
this.urlPathHelper = urlPathHelper;
}
/**
* Set the PathMatcher implementation to use for matching URL paths
* against registered URL patterns. Default is AntPathMatcher.
* @see org.springframework.util.AntPathMatcher
*/
public void setPathMatcher(PathMatcher pathMatcher) {
Assert.notNull(pathMatcher, "PathMatcher must not be null");
this.pathMatcher = pathMatcher;
}
/**
* Return the PathMatcher implementation to use for matching URL paths
* against registered URL patterns.
*/
public PathMatcher getPathMatcher() {
return this.pathMatcher;
}
/** /**
* Set the root handler for this handler mapping, that is, * Set the root handler for this handler mapping, that is,
@ -156,19 +91,6 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
this.lazyInitHandlers = lazyInitHandlers; this.lazyInitHandlers = lazyInitHandlers;
} }
public void setMappedInterceptors(MappedInterceptor[] mappedInterceptors) {
this.mappedInterceptors = new MappedInterceptors(mappedInterceptors);
}
@Override
protected void initInterceptors() {
super.initInterceptors();
if (mappedInterceptors == null) {
this.mappedInterceptors = MappedInterceptors.createFromDeclaredBeans(getApplicationContext());
}
}
/** /**
* Look up a handler for the URL path of the given request. * Look up a handler for the URL path of the given request.
* @param request current HTTP request * @param request current HTTP request
@ -176,7 +98,7 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
*/ */
@Override @Override
protected Object getHandlerInternal(HttpServletRequest request) throws Exception { protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request); String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
Object handler = lookupHandler(lookupPath, request); Object handler = lookupHandler(lookupPath, request);
if (handler == null) { if (handler == null) {
// We need to care for the default handler directly, since we need to // We need to care for the default handler directly, since we need to
@ -287,19 +209,6 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
protected void validateHandler(Object handler, HttpServletRequest request) throws Exception { protected void validateHandler(Object handler, HttpServletRequest request) throws Exception {
} }
@Override
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = super.getHandlerExecutionChain(handler, request);
if (this.mappedInterceptors != null) {
String lookupPath = urlPathHelper.getLookupPathForRequest(request);
HandlerInterceptor[] handlerInterceptors = mappedInterceptors.getInterceptors(lookupPath, pathMatcher);
if (handlerInterceptors.length > 0) {
chain.addInterceptors(handlerInterceptors);
}
}
return chain;
}
/** /**
* Build a handler object for the given raw handler, exposing the actual * Build a handler object for the given raw handler, exposing the actual
* handler, the {@link #PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE}, as well as * handler, the {@link #PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE}, as well as
@ -434,7 +343,7 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
/** /**
* Special interceptor for exposing the * Special interceptor for exposing the
* {@link AbstractUrlHandlerMapping#PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE} attribute. * {@link AbstractUrlHandlerMapping#PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE} attribute.
* @link AbstractUrlHandlerMapping#exposePathWithinMapping * @see AbstractUrlHandlerMapping#exposePathWithinMapping
*/ */
private class PathExposingHandlerInterceptor extends HandlerInterceptorAdapter { private class PathExposingHandlerInterceptor extends HandlerInterceptorAdapter {
@ -459,7 +368,7 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
/** /**
* Special interceptor for exposing the * Special interceptor for exposing the
* {@link AbstractUrlHandlerMapping#URI_TEMPLATE_VARIABLES_ATTRIBUTE} attribute. * {@link AbstractUrlHandlerMapping#URI_TEMPLATE_VARIABLES_ATTRIBUTE} attribute.
* @link AbstractUrlHandlerMapping#exposePathWithinMapping * @see AbstractUrlHandlerMapping#exposePathWithinMapping
*/ */
private class UriTemplateVariablesHandlerInterceptor extends HandlerInterceptorAdapter { private class UriTemplateVariablesHandlerInterceptor extends HandlerInterceptorAdapter {

View File

@ -16,13 +16,16 @@
package org.springframework.web.servlet.handler; package org.springframework.web.servlet.handler;
import org.springframework.util.PathMatcher;
import org.springframework.web.context.request.WebRequestInterceptor; import org.springframework.web.context.request.WebRequestInterceptor;
import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.HandlerInterceptor;
/** /**
* Holds information about a HandlerInterceptor mapped to a path into the application. * Holds information about a HandlerInterceptor mapped to a path into the application.
* Provides a method to match a request path to the mapped path patterns.
* *
* @author Keith Donald * @author Keith Donald
* @author Rossen Stoyanchev
* @since 3.0 * @since 3.0
*/ */
public final class MappedInterceptor { public final class MappedInterceptor {
@ -33,9 +36,9 @@ public final class MappedInterceptor {
/** /**
* Create a new mapped interceptor. * Create a new MappedInterceptor instance.
* @param pathPatterns the path patterns * @param pathPatterns the path patterns to map with a {@code null} value matching to all paths
* @param interceptor the interceptor * @param interceptor the HandlerInterceptor instance to map to the given patterns
*/ */
public MappedInterceptor(String[] pathPatterns, HandlerInterceptor interceptor) { public MappedInterceptor(String[] pathPatterns, HandlerInterceptor interceptor) {
this.pathPatterns = pathPatterns; this.pathPatterns = pathPatterns;
@ -43,9 +46,9 @@ public final class MappedInterceptor {
} }
/** /**
* Create a new mapped interceptor. * Create a new MappedInterceptor instance.
* @param pathPatterns the path patterns * @param pathPatterns the path patterns to map with a {@code null} value matching to all paths
* @param interceptor the interceptor * @param interceptor the WebRequestInterceptor instance to map to the given patterns
*/ */
public MappedInterceptor(String[] pathPatterns, WebRequestInterceptor interceptor) { public MappedInterceptor(String[] pathPatterns, WebRequestInterceptor interceptor) {
this.pathPatterns = pathPatterns; this.pathPatterns = pathPatterns;
@ -67,4 +70,22 @@ public final class MappedInterceptor {
return this.interceptor; return this.interceptor;
} }
/**
* Returns {@code true} if the interceptor applies to the given request path.
* @param lookupPath the current request path
* @param pathMatcher a path matcher for path pattern matching
*/
public boolean matches(String lookupPath, PathMatcher pathMatcher) {
if (pathPatterns == null) {
return true;
}
else {
for (String pathPattern : pathPatterns) {
if (pathMatcher.match(pathPattern, lookupPath)) {
return true;
}
}
return false;
}
}
} }

View File

@ -1,73 +0,0 @@
/*
* Copyright 2002-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.servlet.handler;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.util.PathMatcher;
import org.springframework.web.servlet.HandlerInterceptor;
public final class MappedInterceptors {
private MappedInterceptor[] mappedInterceptors;
public MappedInterceptors(MappedInterceptor[] mappedInterceptors) {
this.mappedInterceptors = mappedInterceptors;
}
public static MappedInterceptors createFromDeclaredBeans(ListableBeanFactory beanFactory) {
Map<String, MappedInterceptor> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(beanFactory,
MappedInterceptor.class, true, false);
if (!beans.isEmpty()) {
return new MappedInterceptors(beans.values().toArray(new MappedInterceptor[beans.size()]));
}
else {
return null;
}
}
public HandlerInterceptor[] getInterceptors(String lookupPath, PathMatcher pathMatcher) {
Set<HandlerInterceptor> interceptors = new LinkedHashSet<HandlerInterceptor>();
for (MappedInterceptor interceptor : this.mappedInterceptors) {
if (matches(interceptor, lookupPath, pathMatcher)) {
interceptors.add(interceptor.getInterceptor());
}
}
return interceptors.toArray(new HandlerInterceptor[interceptors.size()]);
}
private boolean matches(MappedInterceptor interceptor, String lookupPath, PathMatcher pathMatcher) {
String[] pathPatterns = interceptor.getPathPatterns();
if (pathPatterns != null) {
for (String pattern : pathPatterns) {
if (pathMatcher.match(pattern, lookupPath)) {
return true;
}
}
return false;
}
else {
return true;
}
}
}

View File

@ -25,14 +25,13 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.Assert;
import org.springframework.util.PathMatcher; import org.springframework.util.PathMatcher;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.web.HttpMediaTypeNotAcceptableException; import org.springframework.web.HttpMediaTypeNotAcceptableException;
@ -41,12 +40,8 @@ import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.method.HandlerMethod; import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.HandlerMapping; import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping; import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
import org.springframework.web.servlet.handler.MappedInterceptor;
import org.springframework.web.servlet.handler.MappedInterceptors;
import org.springframework.web.servlet.mvc.method.condition.RequestConditionFactory; import org.springframework.web.servlet.mvc.method.condition.RequestConditionFactory;
/** /**
@ -59,36 +54,6 @@ import org.springframework.web.servlet.mvc.method.condition.RequestConditionFact
*/ */
public class RequestMappingHandlerMapping extends AbstractHandlerMethodMapping<RequestMappingInfo> { public class RequestMappingHandlerMapping extends AbstractHandlerMethodMapping<RequestMappingInfo> {
private PathMatcher pathMatcher = new AntPathMatcher();
private MappedInterceptors mappedInterceptors;
/**
* Set the PathMatcher implementation to use for matching URL paths against registered URL patterns. Default is
* AntPathMatcher.
*
* @see org.springframework.util.AntPathMatcher
*/
public void setPathMatcher(PathMatcher pathMatcher) {
Assert.notNull(pathMatcher, "PathMatcher must not be null");
this.pathMatcher = pathMatcher;
}
/**
* Set the {@link MappedInterceptor} instances to use to intercept handler method invocations.
*/
public void setMappedInterceptors(MappedInterceptor[] mappedInterceptors) {
this.mappedInterceptors = new MappedInterceptors(mappedInterceptors);
}
@Override
protected void initInterceptors() {
super.initInterceptors();
if (this.mappedInterceptors == null) {
this.mappedInterceptors = MappedInterceptors.createFromDeclaredBeans(getApplicationContext());
}
}
/** /**
* {@inheritDoc} The handler determination in this method is made based on the presence of a type-level {@link * {@inheritDoc} The handler determination in this method is made based on the presence of a type-level {@link
* Controller} annotation. * Controller} annotation.
@ -127,7 +92,7 @@ public class RequestMappingHandlerMapping extends AbstractHandlerMethodMapping<R
RequestMapping typeAnnot = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class); RequestMapping typeAnnot = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);
if (typeAnnot != null) { if (typeAnnot != null) {
RequestMappingInfo typeMapping = createFromRequestMapping(typeAnnot); RequestMappingInfo typeMapping = createFromRequestMapping(typeAnnot);
return typeMapping.combine(methodMapping, pathMatcher); return typeMapping.combine(methodMapping, getPathMatcher());
} }
else { else {
return methodMapping; return methodMapping;
@ -161,7 +126,7 @@ public class RequestMappingHandlerMapping extends AbstractHandlerMethodMapping<R
protected RequestMappingInfo getMatchingMapping(RequestMappingInfo mapping, protected RequestMappingInfo getMatchingMapping(RequestMappingInfo mapping,
String lookupPath, String lookupPath,
HttpServletRequest request) { HttpServletRequest request) {
return mapping.getMatchingRequestMapping(lookupPath, request, pathMatcher); return mapping.getMatchingRequestMapping(lookupPath, request, getPathMatcher());
} }
/** /**
@ -172,12 +137,18 @@ public class RequestMappingHandlerMapping extends AbstractHandlerMethodMapping<R
return new RequestMappingInfoComparator(lookupPath, request); return new RequestMappingInfoComparator(lookupPath, request);
} }
/**
* Exposes URI template variables and producible media types as request attributes.
*
* @see HandlerMapping#URI_TEMPLATE_VARIABLES_ATTRIBUTE
* @see HandlerMapping#PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE
*/
@Override @Override
protected void handleMatch(RequestMappingInfo info, String lookupPath, HttpServletRequest request) { protected void handleMatch(RequestMappingInfo info, String lookupPath, HttpServletRequest request) {
super.handleMatch(info, lookupPath, request); super.handleMatch(info, lookupPath, request);
String pattern = info.getPatterns().iterator().next(); String pattern = info.getPatterns().iterator().next();
Map<String, String> uriTemplateVariables = pathMatcher.extractUriTemplateVariables(pattern, lookupPath); Map<String, String> uriTemplateVariables = getPathMatcher().extractUriTemplateVariables(pattern, lookupPath);
request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriTemplateVariables); request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriTemplateVariables);
if (!info.getProduces().isEmpty()) { if (!info.getProduces().isEmpty()) {
@ -200,7 +171,7 @@ public class RequestMappingHandlerMapping extends AbstractHandlerMethodMapping<R
Set<MediaType> producibleMediaTypes = new HashSet<MediaType>(); Set<MediaType> producibleMediaTypes = new HashSet<MediaType>();
for (RequestMappingInfo info : requestMappingInfos) { for (RequestMappingInfo info : requestMappingInfos) {
for (String pattern : info.getPatterns()) { for (String pattern : info.getPatterns()) {
if (pathMatcher.match(pattern, lookupPath)) { if (getPathMatcher().match(pattern, lookupPath)) {
if (!info.getMethods().match(request)) { if (!info.getMethods().match(request)) {
for (RequestMethod method : info.getMethods().getMethods()) { for (RequestMethod method : info.getMethods().getMethods()) {
allowedMethods.add(method.name()); allowedMethods.add(method.name());
@ -233,22 +204,6 @@ public class RequestMappingHandlerMapping extends AbstractHandlerMethodMapping<R
} }
} }
/**
* Adds mapped interceptors to the handler execution chain.
*/
@Override
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = super.getHandlerExecutionChain(handler, request);
if (this.mappedInterceptors != null) {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
HandlerInterceptor[] handlerInterceptors = mappedInterceptors.getInterceptors(lookupPath, pathMatcher);
if (handlerInterceptors.length > 0) {
chain.addInterceptors(handlerInterceptors);
}
}
return chain;
}
/** /**
* A comparator for {@link RequestMappingInfo}s. Effective comparison can only be done in the context of a specific * A comparator for {@link RequestMappingInfo}s. Effective comparison can only be done in the context of a specific
* request. For example not all {@link RequestMappingInfo} patterns may apply to the current request. Therefore an * request. For example not all {@link RequestMappingInfo} patterns may apply to the current request. Therefore an
@ -267,7 +222,7 @@ public class RequestMappingHandlerMapping extends AbstractHandlerMethodMapping<R
private List<MediaType> requestAcceptHeader; private List<MediaType> requestAcceptHeader;
public RequestMappingInfoComparator(String lookupPath, HttpServletRequest request) { public RequestMappingInfoComparator(String lookupPath, HttpServletRequest request) {
this.patternComparator = pathMatcher.getPatternComparator(lookupPath); this.patternComparator = getPathMatcher().getPatternComparator(lookupPath);
String acceptHeader = request.getHeader("Accept"); String acceptHeader = request.getHeader("Accept");
this.requestAcceptHeader = MediaType.parseMediaTypes(acceptHeader); this.requestAcceptHeader = MediaType.parseMediaTypes(acceptHeader);
MediaType.sortByQualityValue(this.requestAcceptHeader); MediaType.sortByQualityValue(this.requestAcceptHeader);

View File

@ -16,20 +16,24 @@
package org.springframework.web.servlet.config.annotation; package org.springframework.web.servlet.config.annotation;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.ui.ModelMap; import org.springframework.ui.ModelMap;
import org.springframework.util.AntPathMatcher; import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.context.request.WebRequest; import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.WebRequestInterceptor; import org.springframework.web.context.request.WebRequestInterceptor;
import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.handler.MappedInterceptors; import org.springframework.web.servlet.handler.MappedInterceptor;
import org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter; import org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.theme.ThemeChangeInterceptor; import org.springframework.web.servlet.theme.ThemeChangeInterceptor;
@ -66,15 +70,15 @@ public class InterceptorConfigurerTests {
@Test @Test
public void addInterceptor() { public void addInterceptor() {
configurer.addInterceptor(interceptor1); configurer.addInterceptor(interceptor1);
HandlerInterceptor[] interceptors = getInterceptorsForPath(null); List<HandlerInterceptor> interceptors = getInterceptorsForPath(null);
assertArrayEquals(new HandlerInterceptor[] {interceptor1}, interceptors); assertEquals(Arrays.asList(interceptor1), interceptors);
} }
@Test @Test
public void addInterceptors() { public void addInterceptors() {
configurer.addInterceptors(interceptor1, interceptor2); configurer.addInterceptors(interceptor1, interceptor2);
HandlerInterceptor[] interceptors = getInterceptorsForPath(null); List<HandlerInterceptor> interceptors = getInterceptorsForPath(null);
assertArrayEquals(new HandlerInterceptor[] {interceptor1, interceptor2}, interceptors); assertEquals(Arrays.asList(interceptor1, interceptor2), interceptors);
} }
@Test @Test
@ -82,35 +86,35 @@ public class InterceptorConfigurerTests {
configurer.mapInterceptor(new String[] {"/path1"}, interceptor1); configurer.mapInterceptor(new String[] {"/path1"}, interceptor1);
configurer.mapInterceptor(new String[] {"/path2"}, interceptor2); configurer.mapInterceptor(new String[] {"/path2"}, interceptor2);
assertArrayEquals(new HandlerInterceptor[] {interceptor1}, getInterceptorsForPath("/path1")); assertEquals(Arrays.asList(interceptor1), getInterceptorsForPath("/path1"));
assertArrayEquals(new HandlerInterceptor[] {interceptor2}, getInterceptorsForPath("/path2")); assertEquals(Arrays.asList(interceptor2), getInterceptorsForPath("/path2"));
} }
@Test @Test
public void mapInterceptors() { public void mapInterceptors() {
configurer.mapInterceptors(new String[] {"/path1"}, interceptor1, interceptor2); configurer.mapInterceptors(new String[] {"/path1"}, interceptor1, interceptor2);
assertArrayEquals(new HandlerInterceptor[] {interceptor1, interceptor2}, getInterceptorsForPath("/path1")); assertEquals(Arrays.asList(interceptor1, interceptor2), getInterceptorsForPath("/path1"));
assertArrayEquals(new HandlerInterceptor[] {}, getInterceptorsForPath("/path2")); assertEquals(Arrays.asList(), getInterceptorsForPath("/path2"));
} }
@Test @Test
public void addWebRequestInterceptor() throws Exception { public void addWebRequestInterceptor() throws Exception {
configurer.addInterceptor(webRequestInterceptor1); configurer.addInterceptor(webRequestInterceptor1);
HandlerInterceptor[] interceptors = getInterceptorsForPath(null); List<HandlerInterceptor> interceptors = getInterceptorsForPath(null);
assertEquals(1, interceptors.length); assertEquals(1, interceptors.size());
verifyAdaptedInterceptor(interceptors[0], webRequestInterceptor1); verifyAdaptedInterceptor(interceptors.get(0), webRequestInterceptor1);
} }
@Test @Test
public void addWebRequestInterceptors() throws Exception { public void addWebRequestInterceptors() throws Exception {
configurer.addInterceptors(webRequestInterceptor1, webRequestInterceptor2); configurer.addInterceptors(webRequestInterceptor1, webRequestInterceptor2);
HandlerInterceptor[] interceptors = getInterceptorsForPath(null); List<HandlerInterceptor> interceptors = getInterceptorsForPath(null);
assertEquals(2, interceptors.length); assertEquals(2, interceptors.size());
verifyAdaptedInterceptor(interceptors[0], webRequestInterceptor1); verifyAdaptedInterceptor(interceptors.get(0), webRequestInterceptor1);
verifyAdaptedInterceptor(interceptors[1], webRequestInterceptor2); verifyAdaptedInterceptor(interceptors.get(1), webRequestInterceptor2);
} }
@Test @Test
@ -118,30 +122,36 @@ public class InterceptorConfigurerTests {
configurer.mapInterceptor(new String[] {"/path1"}, webRequestInterceptor1); configurer.mapInterceptor(new String[] {"/path1"}, webRequestInterceptor1);
configurer.mapInterceptor(new String[] {"/path2"}, webRequestInterceptor2); configurer.mapInterceptor(new String[] {"/path2"}, webRequestInterceptor2);
HandlerInterceptor[] interceptors = getInterceptorsForPath("/path1"); List<HandlerInterceptor> interceptors = getInterceptorsForPath("/path1");
assertEquals(1, interceptors.length); assertEquals(1, interceptors.size());
verifyAdaptedInterceptor(interceptors[0], webRequestInterceptor1); verifyAdaptedInterceptor(interceptors.get(0), webRequestInterceptor1);
interceptors = getInterceptorsForPath("/path2"); interceptors = getInterceptorsForPath("/path2");
assertEquals(1, interceptors.length); assertEquals(1, interceptors.size());
verifyAdaptedInterceptor(interceptors[0], webRequestInterceptor2); verifyAdaptedInterceptor(interceptors.get(0), webRequestInterceptor2);
} }
@Test @Test
public void mapWebRequestInterceptor2() throws Exception { public void mapWebRequestInterceptor2() throws Exception {
configurer.mapInterceptors(new String[] {"/path1"}, webRequestInterceptor1, webRequestInterceptor2); configurer.mapInterceptors(new String[] {"/path1"}, webRequestInterceptor1, webRequestInterceptor2);
HandlerInterceptor[] interceptors = getInterceptorsForPath("/path1"); List<HandlerInterceptor> interceptors = getInterceptorsForPath("/path1");
assertEquals(2, interceptors.length); assertEquals(2, interceptors.size());
verifyAdaptedInterceptor(interceptors[0], webRequestInterceptor1); verifyAdaptedInterceptor(interceptors.get(0), webRequestInterceptor1);
verifyAdaptedInterceptor(interceptors[1], webRequestInterceptor2); verifyAdaptedInterceptor(interceptors.get(1), webRequestInterceptor2);
assertEquals(0, getInterceptorsForPath("/path2").length); assertEquals(0, getInterceptorsForPath("/path2").size());
} }
private HandlerInterceptor[] getInterceptorsForPath(String lookupPath) { private List<HandlerInterceptor> getInterceptorsForPath(String lookupPath) {
MappedInterceptors mappedInterceptors = new MappedInterceptors(configurer.getInterceptors()); PathMatcher pathMatcher = new AntPathMatcher();
return mappedInterceptors.getInterceptors(lookupPath, new AntPathMatcher()); List<HandlerInterceptor> result = new ArrayList<HandlerInterceptor>();
for (MappedInterceptor interceptor : configurer.getInterceptors()) {
if (interceptor.matches(lookupPath, pathMatcher)) {
result.add(interceptor.getInterceptor());
}
}
return result;
} }
private void verifyAdaptedInterceptor(HandlerInterceptor interceptor, TestWebRequestInterceptor webInterceptor) private void verifyAdaptedInterceptor(HandlerInterceptor interceptor, TestWebRequestInterceptor webInterceptor)

View File

@ -16,16 +16,25 @@
package org.springframework.web.servlet.config.annotation; package org.springframework.web.servlet.config.annotation;
import static org.easymock.EasyMock.capture;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import org.easymock.Capture; import org.easymock.Capture;
import org.easymock.EasyMock; import org.easymock.EasyMock;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.springframework.format.support.FormattingConversionService; import org.springframework.format.support.FormattingConversionService;
import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.http.converter.StringHttpMessageConverter;
@ -46,9 +55,6 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver; import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;
import static org.easymock.EasyMock.*;
import static org.junit.Assert.*;
/** /**
* A test fixture for WebMvcConfiguration tests. * A test fixture for WebMvcConfiguration tests.
* *
@ -67,17 +73,17 @@ public class WebMvcConfigurationTests {
} }
@Test @Test
public void annotationHandlerAdapter() { public void annotationHandlerAdapter() throws Exception {
Capture<List<HttpMessageConverter<?>>> converters = new Capture<List<HttpMessageConverter<?>>>();
Capture<FormattingConversionService> conversionService = new Capture<FormattingConversionService>(); Capture<FormattingConversionService> conversionService = new Capture<FormattingConversionService>();
Capture<List<HandlerMethodArgumentResolver>> resolvers = new Capture<List<HandlerMethodArgumentResolver>>(); Capture<List<HandlerMethodArgumentResolver>> resolvers = new Capture<List<HandlerMethodArgumentResolver>>();
Capture<List<HandlerMethodReturnValueHandler>> handlers = new Capture<List<HandlerMethodReturnValueHandler>>(); Capture<List<HandlerMethodReturnValueHandler>> handlers = new Capture<List<HandlerMethodReturnValueHandler>>();
Capture<List<HttpMessageConverter<?>>> converters = new Capture<List<HttpMessageConverter<?>>>();
configurer.configureMessageConverters(capture(converters));
expect(configurer.getValidator()).andReturn(null); expect(configurer.getValidator()).andReturn(null);
configurer.addFormatters(capture(conversionService)); configurer.addFormatters(capture(conversionService));
configurer.addArgumentResolvers(capture(resolvers)); configurer.addArgumentResolvers(capture(resolvers));
configurer.addReturnValueHandlers(capture(handlers)); configurer.addReturnValueHandlers(capture(handlers));
configurer.configureMessageConverters(capture(converters));
replay(configurer); replay(configurer);
mvcConfiguration.setConfigurers(Arrays.asList(configurer)); mvcConfiguration.setConfigurers(Arrays.asList(configurer));
@ -107,7 +113,8 @@ public class WebMvcConfigurationTests {
converters.add(new StringHttpMessageConverter()); converters.add(new StringHttpMessageConverter());
} }
}); });
mvcConfiguration.setConfigurers(configurers ); mvcConfiguration = new WebMvcConfiguration();
mvcConfiguration.setConfigurers(configurers);
adapter = mvcConfiguration.requestMappingHandlerAdapter(); adapter = mvcConfiguration.requestMappingHandlerAdapter();
assertEquals("Only one custom converter should be registered", 1, adapter.getMessageConverters().size()); assertEquals("Only one custom converter should be registered", 1, adapter.getMessageConverters().size());
@ -187,7 +194,7 @@ public class WebMvcConfigurationTests {
hm.setApplicationContext(context); hm.setApplicationContext(context);
HandlerExecutionChain chain = hm.getHandler(request); HandlerExecutionChain chain = hm.getHandler(request);
assertNotNull("No chain returned", chain); assertNotNull("No chain returned", chain);
assertNotNull("Expected at one default converter", chain.getInterceptors()); assertNotNull("Expected at least one default converter", chain.getInterceptors());
} }
@Controller @Controller

View File

@ -140,19 +140,25 @@ public class RequestMappingHandlerMappingTests {
} }
@Test @Test
public void mappedInterceptors() { public void mappedInterceptors() throws Exception {
String path = "/handle"; String path = "/foo";
HandlerInterceptor interceptor = new HandlerInterceptorAdapter() {}; HandlerInterceptor interceptor = new HandlerInterceptorAdapter() {};
MappedInterceptor mappedInterceptor = new MappedInterceptor(new String[] {path}, interceptor); MappedInterceptor mappedInterceptor = new MappedInterceptor(new String[] {path}, interceptor);
mapping.setMappedInterceptors(new MappedInterceptor[] { mappedInterceptor }); StaticApplicationContext context = new StaticApplicationContext();
context.registerSingleton("handler", handler.getClass());
HandlerExecutionChain chain = mapping.getHandlerExecutionChain(handler, new MockHttpServletRequest("GET", path)); mapping = new RequestMappingHandlerMapping();
mapping.setInterceptors(new Object[] { mappedInterceptor });
mapping.setApplicationContext(context);
HandlerExecutionChain chain = mapping.getHandler(new MockHttpServletRequest("GET", path));
assertNotNull(chain);
assertNotNull(chain.getInterceptors()); assertNotNull(chain.getInterceptors());
assertSame(interceptor, chain.getInterceptors()[0]); assertSame(interceptor, chain.getInterceptors()[0]);
chain = mapping.getHandlerExecutionChain(handler, new MockHttpServletRequest("GET", "/invalid")); chain = mapping.getHandler(new MockHttpServletRequest("GET", "/invalid"));
assertNull(chain.getInterceptors()); assertNull(chain);
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")