diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java index ebfb201dc32..405317c394a 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java @@ -18,8 +18,6 @@ package org.springframework.web.servlet.config; import java.util.List; -import org.w3c.dom.Element; - import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.config.RuntimeBeanReference; @@ -50,11 +48,12 @@ import org.springframework.web.bind.support.WebArgumentResolver; import org.springframework.web.servlet.handler.ConversionServiceExposingInterceptor; import org.springframework.web.servlet.handler.MappedInterceptor; import org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver; +import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodAdapter; -import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodExceptionResolver; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodMapping; import org.springframework.web.servlet.mvc.method.annotation.support.ServletWebArgumentResolverAdapter; import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver; +import org.w3c.dom.Element; /** * {@link BeanDefinitionParser} that parses the {@code annotation-driven} element to configure a Spring MVC web @@ -146,7 +145,7 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser { mappedCsInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, csInterceptorDef); String mappedInterceptorName = parserContext.getReaderContext().registerWithGeneratedName(mappedCsInterceptorDef); - RootBeanDefinition methodExceptionResolver = new RootBeanDefinition(RequestMappingHandlerMethodExceptionResolver.class); + RootBeanDefinition methodExceptionResolver = new RootBeanDefinition(ExceptionHandlerExceptionResolver.class); methodExceptionResolver.setSource(source); methodExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); methodExceptionResolver.getPropertyValues().add("messageConverters", messageConverters); diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/DefaultServletHandlerConfigurer.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/DefaultServletHandlerConfigurer.java new file mode 100644 index 00000000000..d4f8f78ace6 --- /dev/null +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/DefaultServletHandlerConfigurer.java @@ -0,0 +1,95 @@ +/* + * 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.config.annotation; + +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.ServletContext; + +import org.springframework.web.HttpRequestHandler; +import org.springframework.web.servlet.DispatcherServlet; +import org.springframework.web.servlet.HandlerMapping; +import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; +import org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler; + +/** + * Helps with configuring a handler for serving static resources by forwarding to the Servlet container's default + * Servlet. This is commonly used when the {@link DispatcherServlet} is mapped to "/", which results in cleaner + * URLs (without a servlet prefix) but may need to still allow some requests (e.g. static resources) to be handled + * by the Servlet container's default servlet. + * + *
It is important the configured handler remains last in the order of all {@link HandlerMapping} instances in
+ * the Spring MVC web application context. That is is the case if relying on @{@link EnableMvcConfiguration}.
+ * However, if you register your own HandlerMapping instance sure to set its "order" property to a value lower
+ * than that of the {@link DefaultServletHttpRequestHandler}, which is {@link Integer#MAX_VALUE}.
+ *
+ * @author Rossen Stoyanchev
+ * @since 3.1
+ *
+ * @see ResourceConfigurer
+ */
+public class DefaultServletHandlerConfigurer {
+
+ private DefaultServletHttpRequestHandler requestHandler;
+
+ private final ServletContext servletContext;
+
+ public DefaultServletHandlerConfigurer(ServletContext servletContext) {
+ this.servletContext = servletContext;
+ }
+
+ /**
+ * Enable forwarding to the Servlet container default servlet. The {@link DefaultServletHttpRequestHandler}
+ * will try to auto-detect the default Servlet at startup using a list of known names. Alternatively, you can
+ * specify the name of the default Servlet, see {@link #enable(String)}.
+ */
+ public void enable() {
+ enable(null);
+ }
+
+ /**
+ * Enable forwarding to the Servlet container default servlet specifying explicitly the name of the default
+ * Servlet to forward static resource requests to. This is useful when the default Servlet cannot be detected
+ * (e.g. when using an unknown container or when it has been manually configured).
+ */
+ public void enable(String defaultServletName) {
+ requestHandler = new DefaultServletHttpRequestHandler();
+ requestHandler.setDefaultServletName(defaultServletName);
+ requestHandler.setServletContext(servletContext);
+ }
+
+ /**
+ * Return a {@link SimpleUrlHandlerMapping} instance ordered at {@link Integer#MAX_VALUE} containing a
+ * {@link DefaultServletHttpRequestHandler} mapped to {@code /**}.
+ */
+ protected SimpleUrlHandlerMapping getHandlerMapping() {
+ SimpleUrlHandlerMapping handlerMapping = new SimpleUrlHandlerMapping();
+ handlerMapping.setOrder(Integer.MAX_VALUE);
+ handlerMapping.setUrlMap(getUrlMap());
+ return handlerMapping;
+ }
+
+ private Map To customize the imported configuration you simply implement {@link MvcConfigurer}, or more likely extend
+ * {@link MvcConfigurerSupport} overriding selected methods only. The most obvious place to do this is
+ * the @{@link Configuration} class that enabled the Spring MVC configuration via @{@link EnableMvcConfiguration}.
+ * However any @{@link Configuration} class and more generally any Spring bean can implement {@link MvcConfigurer}
+ * to be detected and given an opportunity to customize Spring MVC configuration at startup.
+ * A number of options are available for customizing the default configuration provided by this class.
+ * See {@link EnableMvcConfiguration} and {@link MvcConfigurer} for details.
+ *
+ * Registers these handler mappings:
+ * Note: that the SimpleUrlHandlerMapping instances above will have empty URL maps and
+ * hence no effect until explicitly configured via {@link MvcConfigurer}.
+ *
+ * Registers these handler adapters:
+ * Registers a {@link HandlerExceptionResolverComposite} with this chain of exception resolvers:
+ * Registers the following others:
+ * Implementations of this interface will find it convenient to extend {@link MvcConfigurerSupport} that
+ * provides default method implementations and allows overriding only methods of interest.
+ *
+ * @author Rossen Stoyanchev
+ * @author Keith Donald
+ * @author David Syer
+ * @since 3.1
+ */
+public interface MvcConfigurer {
+
+ /**
+ * Register application-specific {@link Converter}s and {@link Formatter}s for use in Spring MVC.
+ */
+ void registerFormatters(FormatterRegistry formatterRegistry);
+
+ /**
+ * Customize the list of {@link HttpMessageConverter}s to use when resolving method arguments or handling
+ * return values from @{@link RequestMapping} and @{@link ExceptionHandler} methods.
+ * @param converters the list of converters, initially populated with the default set of converters
+ */
+ void configureMessageConverters(List This implementation is empty.
+ */
+ public void registerFormatters(FormatterRegistry formatterRegistry) {
+ }
+
+ /**
+ * {@inheritDoc}
+ * This implementation is empty.
+ */
+ public void configureMessageConverters(List This implementation is empty.
+ */
+ public void configureValidator(Validator validator) {
+ }
+
+ /**
+ * {@inheritDoc}
+ * This implementation returns {@code null}
+ */
+ public Validator getValidator() {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ * This implementation is empty.
+ */
+ public void addCustomArgumentResolvers(List This implementation is empty.
+ */
+ public void configureHandlerExceptionResolvers(List This implementation is empty.
+ */
+ public void addInterceptors(InterceptorConfigurer interceptorConfigurer) {
+ }
+
+ /**
+ * {@inheritDoc}
+ * This implementation is empty.
+ */
+ public void addViewControllers(ViewControllerConfigurer viewControllerConfigurer) {
+ }
+
+ /**
+ * {@inheritDoc}
+ * This implementation is empty.
+ */
+ public void configureResourceHandling(ResourceConfigurer resourceConfigurer) {
+ }
+
+ /**
+ * {@inheritDoc}
+ * This implementation is empty.
+ */
+ public void configureDefaultServletHandling(DefaultServletHandlerConfigurer handlerConfigurer) {
+ }
+
+}
\ No newline at end of file
diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/ResourceConfigurer.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/ResourceConfigurer.java
new file mode 100644
index 00000000000..576f91f457b
--- /dev/null
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/ResourceConfigurer.java
@@ -0,0 +1,197 @@
+/*
+ * 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.config.annotation;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.ServletContext;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.core.io.Resource;
+import org.springframework.util.Assert;
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.HttpRequestHandler;
+import org.springframework.web.servlet.HandlerMapping;
+import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
+import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
+
+/**
+ * Helps with configuring a handler for serving static resources such as images, css files and others through
+ * Spring MVC including setting cache headers optimized for efficient loading in a web browser. Resources can
+ * be served out of locations under web application root, from the classpath, and others.
+ *
+ * To configure resource handling, use {@link #addPathMappings(String...)} to add one or more URL path patterns
+ * within the current Servlet context, to use for serving resources from the handler, such as {@code "/resources/**"}.
+ *
+ * Then use {@link #addResourceLocations(String...)} to add one or more locations from which to serve
+ * static content. For example, {{@code "/"}, {@code "classpath:/META-INF/public-web-resources/"}} allows resources
+ * to be served both from the web application root and from any JAR on the classpath that contains a
+ * {@code /META-INF/public-web-resources/} directory, with resources in the web application root taking precedence.
+ *
+ * Optionally use {@link #setCachePeriod(Integer)} to specify the cache period for the resources served by the
+ * handler and {@link #setOrder(int)} to set the order in which to serve requests relative to other
+ * {@link HandlerMapping} instances in the Spring MVC web application context.
+ *
+ * @author Rossen Stoyanchev
+ * @since 3.1
+ *
+ * @see DefaultServletHandlerConfigurer
+ */
+public class ResourceConfigurer {
+
+ private final List For example, a value of {@code "/"} will allow resources to be served both from the web
+ * application root. Also see {@link #addResourceLocations(String...)} for mapping several resource locations.
+ * @return the same {@link ResourceConfigurer} instance for chained method invocation
+ */
+ public ResourceConfigurer addResourceLocation(String resourceLocation) {
+ return addResourceLocations(resourceLocation);
+ }
+
+ /**
+ * Add one or more resource locations from which to serve static content. Each location must point to a valid
+ * directory. Multiple locations may be specified as a comma-separated list, and the locations will be checked
+ * for a given resource in the order specified.
+ * For example, {{@code "/"}, {@code "classpath:/META-INF/public-web-resources/"}} allows resources to
+ * be served both from the web application root and from any JAR on the classpath that contains a
+ * {@code /META-INF/public-web-resources/} directory, with resources in the web application root taking precedence.
+ * @return the same {@link ResourceConfigurer} instance for chained method invocation
+ */
+ public ResourceConfigurer addResourceLocations(String...resourceLocations) {
+ for (String location : resourceLocations) {
+ this.locations.add(applicationContext.getResource(location));
+ }
+ return this;
+ }
+
+ /**
+ * Specify the cache period for the resources served by the resource handler, in seconds. The default is to not
+ * send any cache headers but to rely on last-modified timestamps only. Set to 0 in order to send cache headers
+ * that prevent caching, or to a positive number of seconds to send cache headers with the given max-age value.
+ * @param cachePeriod the time to cache resources in seconds
+ * @return the same {@link ResourceConfigurer} instance for chained method invocation
+ */
+ public ResourceConfigurer setCachePeriod(Integer cachePeriod) {
+ this.cachePeriod = cachePeriod;
+ return this;
+ }
+
+ /**
+ * Get the cache period for static resources served by the resource handler.
+ */
+ public Integer getCachePeriod() {
+ return cachePeriod;
+ }
+
+ /**
+ * Specify the order in which to serve static resources relative to other {@link HandlerMapping} instances in the
+ * Spring MVC web application context. The default value is {@code Integer.MAX_VALUE-1}.
+ */
+ public ResourceConfigurer setOrder(int order) {
+ this.order = order;
+ return this;
+ }
+
+ /**
+ * Get the order in which to serve static resources relative other {@link HandlerMapping} instances.
+ * @return the same {@link ResourceConfigurer} instance for chained method invocation
+ */
+ public Integer getOrder() {
+ return order;
+ }
+
+ /**
+ * Return a {@link SimpleUrlHandlerMapping} with a {@link ResourceHttpRequestHandler} mapped to one or more
+ * URL path patterns. If the no path patterns were specified, the HandlerMapping returned contains an empty map.
+ */
+ protected SimpleUrlHandlerMapping getHandlerMapping() {
+ SimpleUrlHandlerMapping handlerMapping = new SimpleUrlHandlerMapping();
+ handlerMapping.setOrder(order);
+ handlerMapping.setUrlMap(getUrlMap());
+ return handlerMapping;
+ }
+
+ private Map This method creates a {@link ServletRequestDataBinder} instance that also adds URI template variables to
+ * the values used in data binding.
+ * Subclasses wishing to override this method to provide their own ServletRequestDataBinder type can use the
+ * {@link #addUriTemplateVariables(MutablePropertyValues)} method to include URI template variables as follows:
+ * If the underlying method has a {@link ResponseStatus} instruction, the status on the response is set
+ *
+ * If the underlying method has a {@link ResponseStatus} instruction, the status on the response is set
* accordingly after the method is invoked but before the return value is handled.
- *
+ *
* @author Rossen Stoyanchev
* @since 3.1
* @see #invokeAndHandle(NativeWebRequest, ModelAndViewContainer, Object...)
@@ -47,9 +46,9 @@ import org.springframework.web.servlet.mvc.method.annotation.support.ServletResp
public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
private HttpStatus responseStatus;
-
+
private String responseReason;
-
+
private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
public void setHandlerMethodReturnValueHandlers(HandlerMethodReturnValueHandlerComposite returnValueHandlers) {
@@ -72,26 +71,26 @@ public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
}
/**
- * Invokes the method and handles the return value through a registered {@link HandlerMethodReturnValueHandler}.
+ * Invokes the method and handles the return value through a registered {@link HandlerMethodReturnValueHandler}.
* Return value handling may be skipped entirely when the method returns {@code null} (also possibly due
* to a {@code void} return type) and one of the following additional conditions is true:
* After the return value is handled, callers of this method can use the {@link ModelAndViewContainer}
+ * After the return value is handled, callers of this method can use the {@link ModelAndViewContainer}
* to gain access to model attributes, view selection choices, and to check if view resolution is even needed.
- *
+ *
* @param request the current request
* @param mavContainer the {@link ModelAndViewContainer} for the current request
* @param providedArgs argument values to try to use without the need for view resolution
*/
- public final void invokeAndHandle(NativeWebRequest request,
- ModelAndViewContainer mavContainer,
+ public final void invokeAndHandle(NativeWebRequest request,
+ ModelAndViewContainer mavContainer,
Object...providedArgs) throws Exception {
if (!returnValueHandlers.supportsReturnType(getReturnType())) {
@@ -108,7 +107,7 @@ public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
return;
}
}
-
+
mavContainer.setResolveView(true);
returnValueHandlers.handleReturnValue(returnValue, getReturnType(), mavContainer, request);
diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletModelAttributeMethodProcessor.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletModelAttributeMethodProcessor.java
index 92ce76483c4..7d5c900ff67 100644
--- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletModelAttributeMethodProcessor.java
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ServletModelAttributeMethodProcessor.java
@@ -26,9 +26,9 @@ import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.annotation.support.ModelAttributeMethodProcessor;
/**
- * A Servlet-specific {@link ModelAttributeMethodProcessor} variant that casts the {@link WebDataBinder}
+ * A Servlet-specific {@link ModelAttributeMethodProcessor} variant that casts the {@link WebDataBinder}
* instance to {@link ServletRequestDataBinder} prior to invoking data binding.
- *
+ *
* @author Rossen Stoyanchev
* @since 3.1
*/
@@ -36,7 +36,7 @@ public class ServletModelAttributeMethodProcessor extends ModelAttributeMethodPr
/**
* @param useDefaultResolution in default resolution mode a method argument that isn't a simple type, as
- * defined in {@link BeanUtils#isSimpleProperty(Class)}, is treated as a model attribute even if it doesn't
+ * defined in {@link BeanUtils#isSimpleProperty(Class)}, is treated as a model attribute even if it doesn't
* have an @{@link ModelAttribute} annotation with its name derived from the model attribute type.
*/
public ServletModelAttributeMethodProcessor(boolean useDefaultResolution) {
@@ -44,12 +44,15 @@ public class ServletModelAttributeMethodProcessor extends ModelAttributeMethodPr
}
/**
- * Expects the data binder to be an instance of {@link ServletRequestDataBinder}.
+ * {@inheritDoc}
+ * This method downcasts the binder instance to {@link ServletRequestDataBinder} and invokes
+ * its bind method passing a {@link ServletRequest} to it.
*/
@Override
protected void doBind(WebDataBinder binder, NativeWebRequest request) {
ServletRequest servletRequest = request.getNativeRequest(ServletRequest.class);
- ((ServletRequestDataBinder) binder).bind(servletRequest);
+ ServletRequestDataBinder servletBinder = (ServletRequestDataBinder) binder;
+ servletBinder.bind(servletRequest);
}
}
\ No newline at end of file
diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ViewMethodReturnValueHandler.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ViewMethodReturnValueHandler.java
index 76efe6fee5e..eb563cb5a76 100644
--- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ViewMethodReturnValueHandler.java
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ViewMethodReturnValueHandler.java
@@ -17,31 +17,39 @@
package org.springframework.web.servlet.mvc.method.annotation.support;
import org.springframework.core.MethodParameter;
+import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.NativeWebRequest;
-import org.springframework.web.method.annotation.support.ModelAttributeMethodProcessor;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;
+import org.springframework.web.servlet.RequestToViewNameTranslator;
import org.springframework.web.servlet.View;
+import org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator;
/**
- * Handles return values that are of type {@link View} or {@link String} (i.e. a logical view name).
- * Since a {@link String} return value may handled in different ways, especially in combination with method
- * annotations, this handler should be registered after return value handlers that look for method annotations
- * such as the {@link ModelAttributeMethodProcessor} and the {@link RequestResponseBodyMethodProcessor}.
- *
+ * Handles return values that are of type {@code void}, {@code String} (i.e. logical view name), or {@link View}.
+ *
+ * A {@code null} return value, either due to a void return type or as the actual value returned from a
+ * method is left unhandled, leaving it to the configured {@link RequestToViewNameTranslator} to resolve the
+ * request to an actual view name. By default it is the {@link DefaultRequestToViewNameTranslator}.
+ *
+ * Since a {@link String} return value may handled in different ways, especially in combination with method
+ * annotations such as @{@link ModelAttribute} and @{@link ResponseBody}, this handler should be ordered after
+ * return value handlers that support method annotations.
+ *
* @author Rossen Stoyanchev
* @since 3.1
*/
public class ViewMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
-
+
public boolean supportsReturnType(MethodParameter returnType) {
- Class> paramType = returnType.getParameterType();
- return (View.class.isAssignableFrom(paramType) || (String.class.equals(paramType)));
+ Class> type = returnType.getParameterType();
+ return (void.class.equals(type) || String.class.equals(type) || View.class.isAssignableFrom(type));
}
- public void handleReturnValue(Object returnValue,
- MethodParameter returnType,
- ModelAndViewContainer mavContainer,
+ public void handleReturnValue(Object returnValue,
+ MethodParameter returnType,
+ ModelAndViewContainer mavContainer,
NativeWebRequest webRequest) throws Exception {
if (returnValue == null) {
return;
diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/DefaultServletHandlerConfigurerTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/DefaultServletHandlerConfigurerTests.java
new file mode 100644
index 00000000000..874ef655d99
--- /dev/null
+++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/DefaultServletHandlerConfigurerTests.java
@@ -0,0 +1,102 @@
+/*
+ * 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.config.annotation;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import javax.servlet.RequestDispatcher;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.mock.web.MockRequestDispatcher;
+import org.springframework.mock.web.MockServletContext;
+import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
+import org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler;
+
+/**
+ * Test fixture with a {@link DefaultServletHandlerConfigurer}.
+ *
+ * @author Rossen Stoyanchev
+ */
+public class DefaultServletHandlerConfigurerTests {
+
+ private DefaultServletHandlerConfigurer configurer;
+
+ private DispatchingMockServletContext servletContext;
+
+ private MockHttpServletResponse response;
+
+ @Before
+ public void setUp() {
+ response = new MockHttpServletResponse();
+ servletContext = new DispatchingMockServletContext();
+ configurer = new DefaultServletHandlerConfigurer(servletContext);
+ }
+
+ @Test
+ public void notEnabled() {
+ assertTrue(configurer.getHandlerMapping().getUrlMap().isEmpty());
+ }
+
+ @Test
+ public void enable() throws Exception {
+ configurer.enable();
+ SimpleUrlHandlerMapping handlerMapping = configurer.getHandlerMapping();
+ DefaultServletHttpRequestHandler handler = (DefaultServletHttpRequestHandler) handlerMapping.getUrlMap().get("/**");
+
+ assertNotNull(handler);
+ assertEquals(Integer.MAX_VALUE, handlerMapping.getOrder());
+
+ handler.handleRequest(new MockHttpServletRequest(), response);
+
+ String expected = "default";
+ assertEquals("The ServletContext was not called with the default servlet name", expected, servletContext.url);
+ assertEquals("The request was not forwarded", expected, response.getForwardedUrl());
+ }
+
+ @Test
+ public void enableWithServletName() throws Exception {
+ configurer.enable("defaultServlet");
+ SimpleUrlHandlerMapping handlerMapping = configurer.getHandlerMapping();
+ DefaultServletHttpRequestHandler handler = (DefaultServletHttpRequestHandler) handlerMapping.getUrlMap().get("/**");
+
+ assertNotNull(handler);
+ assertEquals(Integer.MAX_VALUE, handlerMapping.getOrder());
+
+ handler.handleRequest(new MockHttpServletRequest(), response);
+
+ String expected = "defaultServlet";
+ assertEquals("The ServletContext was not called with the default servlet name", expected, servletContext.url);
+ assertEquals("The request was not forwarded", expected, response.getForwardedUrl());
+ }
+
+ private static class DispatchingMockServletContext extends MockServletContext {
+
+ private String url;
+
+ @Override
+ public RequestDispatcher getNamedDispatcher(String url) {
+ this.url = url;
+ return new MockRequestDispatcher(url);
+ }
+ }
+
+}
diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/InterceptorConfigurerTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/InterceptorConfigurerTests.java
new file mode 100644
index 00000000000..1cf2590f00b
--- /dev/null
+++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/InterceptorConfigurerTests.java
@@ -0,0 +1,168 @@
+/*
+ * 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.config.annotation;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.ui.ModelMap;
+import org.springframework.util.AntPathMatcher;
+import org.springframework.web.context.request.WebRequest;
+import org.springframework.web.context.request.WebRequestInterceptor;
+import org.springframework.web.servlet.HandlerInterceptor;
+import org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter;
+import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
+import org.springframework.web.servlet.theme.ThemeChangeInterceptor;
+
+/**
+ * Test fixture with a {@link InterceptorConfigurer}, two {@link HandlerInterceptor}s and two
+ * {@link WebRequestInterceptor}s.
+ *
+ * @author Rossen Stoyanchev
+ */
+public class InterceptorConfigurerTests {
+
+ private InterceptorConfigurer configurer;
+
+ private final HandlerInterceptor interceptor1 = new LocaleChangeInterceptor();
+
+ private final HandlerInterceptor interceptor2 = new ThemeChangeInterceptor();
+
+ private TestWebRequestInterceptor webRequestInterceptor1;
+
+ private TestWebRequestInterceptor webRequestInterceptor2;
+
+ private final MockHttpServletRequest request = new MockHttpServletRequest();
+
+ private final MockHttpServletResponse response = new MockHttpServletResponse();
+
+ @Before
+ public void setUp() {
+ configurer = new InterceptorConfigurer();
+ webRequestInterceptor1 = new TestWebRequestInterceptor();
+ webRequestInterceptor2 = new TestWebRequestInterceptor();
+ }
+
+ @Test
+ public void addInterceptor() {
+ configurer.addInterceptor(interceptor1);
+ HandlerInterceptor[] interceptors = getInterceptorsForPath(null);
+ assertArrayEquals(new HandlerInterceptor[] {interceptor1}, interceptors);
+ }
+
+ @Test
+ public void addInterceptors() {
+ configurer.addInterceptors(interceptor1, interceptor2);
+ HandlerInterceptor[] interceptors = getInterceptorsForPath(null);
+ assertArrayEquals(new HandlerInterceptor[] {interceptor1, interceptor2}, interceptors);
+ }
+
+ @Test
+ public void mapInterceptor() {
+ configurer.mapInterceptor(new String[] {"/path1"}, interceptor1);
+ configurer.mapInterceptor(new String[] {"/path2"}, interceptor2);
+
+ assertArrayEquals(new HandlerInterceptor[] {interceptor1}, getInterceptorsForPath("/path1"));
+ assertArrayEquals(new HandlerInterceptor[] {interceptor2}, getInterceptorsForPath("/path2"));
+ }
+
+ @Test
+ public void mapInterceptors() {
+ configurer.mapInterceptors(new String[] {"/path1"}, interceptor1, interceptor2);
+
+ assertArrayEquals(new HandlerInterceptor[] {interceptor1, interceptor2}, getInterceptorsForPath("/path1"));
+ assertArrayEquals(new HandlerInterceptor[] {}, getInterceptorsForPath("/path2"));
+ }
+
+ @Test
+ public void addWebRequestInterceptor() throws Exception {
+ configurer.addInterceptor(webRequestInterceptor1);
+ HandlerInterceptor[] interceptors = getInterceptorsForPath(null);
+
+ assertEquals(1, interceptors.length);
+ verifyAdaptedInterceptor(interceptors[0], webRequestInterceptor1);
+ }
+
+ @Test
+ public void addWebRequestInterceptors() throws Exception {
+ configurer.addInterceptors(webRequestInterceptor1, webRequestInterceptor2);
+ HandlerInterceptor[] interceptors = getInterceptorsForPath(null);
+
+ assertEquals(2, interceptors.length);
+ verifyAdaptedInterceptor(interceptors[0], webRequestInterceptor1);
+ verifyAdaptedInterceptor(interceptors[1], webRequestInterceptor2);
+ }
+
+ @Test
+ public void mapWebRequestInterceptor() throws Exception {
+ configurer.mapInterceptor(new String[] {"/path1"}, webRequestInterceptor1);
+ configurer.mapInterceptor(new String[] {"/path2"}, webRequestInterceptor2);
+
+ HandlerInterceptor[] interceptors = getInterceptorsForPath("/path1");
+ assertEquals(1, interceptors.length);
+ verifyAdaptedInterceptor(interceptors[0], webRequestInterceptor1);
+
+ interceptors = getInterceptorsForPath("/path2");
+ assertEquals(1, interceptors.length);
+ verifyAdaptedInterceptor(interceptors[0], webRequestInterceptor2);
+ }
+
+ @Test
+ public void mapWebRequestInterceptor2() throws Exception {
+ configurer.mapInterceptors(new String[] {"/path1"}, webRequestInterceptor1, webRequestInterceptor2);
+
+ HandlerInterceptor[] interceptors = getInterceptorsForPath("/path1");
+ assertEquals(2, interceptors.length);
+ verifyAdaptedInterceptor(interceptors[0], webRequestInterceptor1);
+ verifyAdaptedInterceptor(interceptors[1], webRequestInterceptor2);
+
+ assertEquals(0, getInterceptorsForPath("/path2").length);
+ }
+
+ private HandlerInterceptor[] getInterceptorsForPath(String lookupPath) {
+ return configurer.getMappedInterceptors().getInterceptors(lookupPath, new AntPathMatcher());
+ }
+
+ private void verifyAdaptedInterceptor(HandlerInterceptor interceptor, TestWebRequestInterceptor webInterceptor)
+ throws Exception {
+ assertTrue(interceptor instanceof WebRequestHandlerInterceptorAdapter);
+ interceptor.preHandle(request, response, null);
+ assertTrue(webInterceptor.preHandleInvoked);
+ }
+
+ private static class TestWebRequestInterceptor implements WebRequestInterceptor {
+
+ private boolean preHandleInvoked = false;
+
+ public void preHandle(WebRequest request) throws Exception {
+ preHandleInvoked = true;
+ }
+
+ public void postHandle(WebRequest request, ModelMap model) throws Exception {
+ }
+
+ public void afterCompletion(WebRequest request, Exception ex) throws Exception {
+ }
+
+ }
+
+}
diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/MvcConfigurationTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/MvcConfigurationTests.java
new file mode 100644
index 00000000000..96716547228
--- /dev/null
+++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/MvcConfigurationTests.java
@@ -0,0 +1,132 @@
+/*
+ * 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.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.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.easymock.Capture;
+import org.easymock.EasyMock;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.format.support.FormattingConversionService;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
+import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
+import org.springframework.web.method.support.HandlerMethodArgumentResolver;
+import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
+import org.springframework.web.servlet.HandlerExceptionResolver;
+import org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver;
+import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
+import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodAdapter;
+import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;
+
+/**
+ * A test fixture with an {@link MvcConfiguration} and a mock {@link MvcConfigurer} for verifying delegation.
+ *
+ * @author Rossen Stoyanchev
+ */
+public class MvcConfigurationTests {
+
+ private MvcConfiguration mvcConfiguration;
+
+ private MvcConfigurer configurer;
+
+ @Before
+ public void setUp() {
+ configurer = EasyMock.createMock(MvcConfigurer.class);
+ mvcConfiguration = new MvcConfiguration();
+ mvcConfiguration.setConfigurers(Arrays.asList(configurer));
+ }
+
+ @Test
+ public void annotationHandlerAdapter() {
+ Capture
+ * @Configuration
+ * @EnableMvcConfiguration
+ * @ComponentScan(
+ * basePackageClasses = { MyMvcConfiguration.class },
+ * excludeFilters = { @Filter(type = FilterType.ANNOTATION, value = Configuration.class) }
+ * )
+ * public class MyMvcConfiguration {
+ *
+ * }
+ *
+ *
+ * @Configuration
+ * @EnableMvcConfiguration
+ * @ComponentScan(
+ * basePackageClasses = { MyMvcConfiguration.class },
+ * excludeFilters = { @Filter(type = FilterType.ANNOTATION, value = Configuration.class) }
+ * )
+ * public class MyMvcConfiguration extends MvcConfigurerSupport {
+ *
+ * @Override
+ * public void registerFormatters(FormatterRegistry formatterRegistry) {
+ * formatterRegistry.addConverter(new MyConverter());
+ * }
+ *
+ * @Override
+ * public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
+ * converters.add(new MyHttpMessageConverter());
+ * }
+ *
+ * ...
+ *
+ * }
+ *
+ *
+ * @see MvcConfigurer
+ * @see MvcConfigurerSupport
+ *
+ * @author Dave Syer
+ * @author Rossen Stoyanchev
+ * @since 3.1
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+@Documented
+@Import(MvcConfiguration.class)
+public @interface EnableMvcConfiguration {
+}
diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/InterceptorConfigurer.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/InterceptorConfigurer.java
new file mode 100644
index 00000000000..e52c7b4e2a7
--- /dev/null
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/InterceptorConfigurer.java
@@ -0,0 +1,126 @@
+/*
+ * 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.config.annotation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.springframework.util.Assert;
+import org.springframework.web.context.request.WebRequestInterceptor;
+import org.springframework.web.servlet.HandlerInterceptor;
+import org.springframework.web.servlet.HandlerMapping;
+import org.springframework.web.servlet.handler.MappedInterceptor;
+import org.springframework.web.servlet.handler.MappedInterceptors;
+import org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter;
+
+/**
+ * Helps with configuring an ordered set of Spring MVC interceptors of type {@link HandlerInterceptor} or
+ * {@link WebRequestInterceptor}. Registered interceptors will generally be detected by all {@link HandlerMapping}
+ * instances in a Spring MVC web application context. Interceptors can be added with a set of path patterns to
+ * which they should apply.
+ *
+ * @author Rossen Stoyanchev
+ * @since 3.1
+ */
+public class InterceptorConfigurer {
+
+ private final List
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * @see EnableMvcConfiguration
+ * @see MvcConfigurer
+ *
+ * @author Rossen Stoyanchev
+ * @since 3.1
+ */
+@Configuration
+class MvcConfiguration implements ApplicationContextAware, ServletContextAware {
+
+ private final MvcConfigurerComposite configurers = new MvcConfigurerComposite();
+
+ private ServletContext servletContext;
+
+ private ApplicationContext applicationContext;
+
+ @Autowired(required = false)
+ public void setConfigurers(List
+ * return new CustomServletRequestDataBinder(target, objectName) {
+ * protected void doBind(MutablePropertyValues mpvs) {
+ * addUriTemplateVariables(mpvs);
+ * super.doBind(mpvs);
+ * }
+ * };
+ *
*/
@Override
protected WebDataBinder createBinderInstance(Object target, String objectName) {
- return new ServletRequestPathVarDataBinder(target, objectName);
+ return new ServletRequestDataBinder(target, objectName) {
+
+ protected void doBind(MutablePropertyValues mpvs) {
+ addUriTemplateVariables(mpvs);
+ super.doBind(mpvs);
+ }
+ };
}
/**
- * Adds URI template variables to the map of request values used to do data binding.
+ * Adds URI template variables to the given property values.
+ * @param mpvs the PropertyValues to add URI template variables to
*/
- private static class ServletRequestPathVarDataBinder extends ServletRequestDataBinder {
-
- public ServletRequestPathVarDataBinder(Object target, String objectName) {
- super(target, objectName);
- }
-
- @SuppressWarnings("unchecked")
- @Override
- protected void doBind(MutablePropertyValues mpvs) {
- RequestAttributes requestAttrs = RequestContextHolder.getRequestAttributes();
- if (requestAttrs != null) {
- String key = HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE;
- int scope = RequestAttributes.SCOPE_REQUEST;
- Map
- *
- * > resolvers = new Capture
>();
+ Capture
> handlers = new Capture
>();
+ Capture
>> converters = new Capture
>>();
+
+ expect(configurer.getValidator()).andReturn(null);
+ configurer.registerFormatters(capture(conversionService));
+ configurer.addCustomArgumentResolvers(capture(resolvers));
+ configurer.addCustomReturnValueHandlers(capture(handlers));
+ configurer.configureMessageConverters(capture(converters));
+ replay(configurer);
+
+ RequestMappingHandlerMethodAdapter adapter = mvcConfiguration.requestMappingHandlerAdapter();
+
+ ConfigurableWebBindingInitializer initializer = (ConfigurableWebBindingInitializer) adapter.getWebBindingInitializer();
+ assertSame(conversionService.getValue(), initializer.getConversionService());
+ assertTrue(initializer.getValidator() instanceof LocalValidatorFactoryBean);
+
+ assertEquals(0, resolvers.getValue().size());
+ assertEquals(0, handlers.getValue().size());
+ assertTrue(converters.getValue().size() > 0);
+ assertEquals(converters.getValue(), adapter.getMessageConverters());
+
+ verify(configurer);
+ }
+
+ @Test
+ public void getCustomValidator() {
+ expect(configurer.getValidator()).andReturn(new LocalValidatorFactoryBean());
+ replay(configurer);
+
+ mvcConfiguration.validator();
+
+ verify(configurer);
+ }
+
+ @Test
+ public void configureValidator() {
+ expect(configurer.getValidator()).andReturn(null);
+ replay(configurer);
+
+ mvcConfiguration.validator();
+
+ verify(configurer);
+ }
+
+ @Test
+ public void handlerExceptionResolver() throws Exception {
+ Capture
>> converters = new Capture
>>();
+ Capture
> exceptionResolvers = new Capture
>();
+
+ configurer.configureMessageConverters(capture(converters));
+ configurer.configureHandlerExceptionResolvers(capture(exceptionResolvers));
+ replay(configurer);
+
+ mvcConfiguration.handlerExceptionResolver();
+
+ assertEquals(3, exceptionResolvers.getValue().size());
+ assertTrue(exceptionResolvers.getValue().get(0) instanceof ExceptionHandlerExceptionResolver);
+ assertTrue(exceptionResolvers.getValue().get(1) instanceof ResponseStatusExceptionResolver);
+ assertTrue(exceptionResolvers.getValue().get(2) instanceof DefaultHandlerExceptionResolver);
+ assertTrue(converters.getValue().size() > 0);
+
+ verify(configurer);
+ }
+
+}
diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/ResourceConfigurerTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/ResourceConfigurerTests.java
new file mode 100644
index 00000000000..ba8d59488a7
--- /dev/null
+++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/ResourceConfigurerTests.java
@@ -0,0 +1,89 @@
+/*
+ * 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.config.annotation;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.mock.web.MockServletContext;
+import org.springframework.web.context.support.GenericWebApplicationContext;
+import org.springframework.web.servlet.HandlerMapping;
+import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
+
+/**
+ * Test fixture with a {@link ResourceConfigurer}.
+ *
+ * @author Rossen Stoyanchev
+ */
+public class ResourceConfigurerTests {
+
+ private ResourceConfigurer configurer;
+
+ private MockHttpServletResponse response;
+
+ @Before
+ public void setUp() {
+ configurer = new ResourceConfigurer(new GenericWebApplicationContext(), new MockServletContext());
+ configurer.addPathMapping("/resources/**");
+ configurer.addResourceLocation("classpath:org/springframework/web/servlet/config/annotation/");
+
+ response = new MockHttpServletResponse();
+ }
+
+ @Test
+ public void noMappings() throws Exception {
+ configurer = new ResourceConfigurer(new GenericWebApplicationContext(), new MockServletContext());
+ assertTrue(configurer.getHandlerMapping().getUrlMap().isEmpty());
+ }
+
+ @Test
+ public void mapPathToLocation() throws Exception {
+ MockHttpServletRequest request = new MockHttpServletRequest();
+ request.setMethod("GET");
+ request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "/testStylesheet.css");
+
+ ResourceHttpRequestHandler handler = getResourceHandler("/resources/**");
+ handler.handleRequest(request, response);
+
+ assertEquals("test stylesheet content", response.getContentAsString());
+ }
+
+ @Test
+ public void cachePeriod() {
+ assertEquals(-1, getResourceHandler("/resources/**").getCacheSeconds());
+
+ configurer.setCachePeriod(0);
+ assertEquals(0, getResourceHandler("/resources/**").getCacheSeconds());
+ }
+
+ @Test
+ public void order() {
+ assertEquals(Integer.MAX_VALUE -1, configurer.getHandlerMapping().getOrder());
+
+ configurer.setOrder(0);
+ assertEquals(0, configurer.getHandlerMapping().getOrder());
+ }
+
+ private ResourceHttpRequestHandler getResourceHandler(String pathPattern) {
+ return (ResourceHttpRequestHandler) configurer.getHandlerMapping().getUrlMap().get(pathPattern);
+ }
+
+}
diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/ViewControllerConfigurerTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/ViewControllerConfigurerTests.java
new file mode 100644
index 00000000000..f0edd47decf
--- /dev/null
+++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/ViewControllerConfigurerTests.java
@@ -0,0 +1,75 @@
+/*
+ * 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.config.annotation;
+
+import static org.junit.Assert.*;
+
+import java.util.Map;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
+import org.springframework.web.servlet.mvc.ParameterizableViewController;
+
+/**
+ * Test fixture with a {@link ViewControllerConfigurer}.
+ *
+ * @author Rossen Stoyanchev
+ */
+public class ViewControllerConfigurerTests {
+
+ private ViewControllerConfigurer configurer;
+
+ @Before
+ public void setUp() {
+ configurer = new ViewControllerConfigurer();
+ }
+
+ @Test
+ public void noMappings() throws Exception {
+ Map