From ab033086f98e633fa7314edf3adfab67fe9bd85b Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Wed, 15 Jun 2011 08:06:42 +0000 Subject: [PATCH] SPR-8454 Introduce Registration style objects, rename several Spring MVC *Configurer helpers to *Registry, add more tests --- .../DefaultServletHandlerConfigurer.java | 71 ++-- .../DelegatingWebMvcConfiguration.java | 22 +- .../config/annotation/EnableWebMvc.java | 15 +- .../annotation/InterceptorConfigurer.java | 134 -------- .../annotation/InterceptorRegistration.java | 68 ++++ .../annotation/InterceptorRegistry.java | 75 +++++ .../config/annotation/ResourceConfigurer.java | 197 ----------- .../ResourceHandlerRegistration.java | 105 ++++++ .../annotation/ResourceHandlerRegistry.java | 111 ++++++ .../annotation/ViewControllerConfigurer.java | 87 ----- .../ViewControllerRegistration.java | 70 ++++ .../annotation/ViewControllerRegistry.java | 77 +++++ .../WebMvcConfigurationSupport.java | 188 +++++------ .../config/annotation/WebMvcConfigurer.java | 76 ++--- .../annotation/WebMvcConfigurerAdapter.java | 9 +- .../annotation/WebMvcConfigurerComposite.java | 12 +- ...tationDrivenBeanDefinitionParserTests.java | 2 +- .../DefaultServletHandlerConfigurerTests.java | 13 +- ...> DelegatingWebMvcConfigurationTests.java} | 65 +--- ...sts.java => InterceptorRegistryTests.java} | 60 ++-- ...java => ResourceHandlerRegistryTests.java} | 43 +-- ....java => ViewControllerRegistryTests.java} | 53 +-- .../WebMvcConfigurationSupportTests.java | 315 ++++++++++++++++++ 23 files changed, 1101 insertions(+), 767 deletions(-) delete mode 100644 org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/InterceptorConfigurer.java create mode 100644 org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/InterceptorRegistration.java create mode 100644 org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/InterceptorRegistry.java delete mode 100644 org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/ResourceConfigurer.java create mode 100644 org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistration.java create mode 100644 org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistry.java delete mode 100644 org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/ViewControllerConfigurer.java create mode 100644 org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/ViewControllerRegistration.java create mode 100644 org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/ViewControllerRegistry.java rename org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/{WebMvcConfigurationTests.java => DelegatingWebMvcConfigurationTests.java} (73%) rename org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/{InterceptorConfigurerTests.java => InterceptorRegistryTests.java} (75%) rename org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/{ResourceConfigurerTests.java => ResourceHandlerRegistryTests.java} (55%) rename org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/{ViewControllerConfigurerTests.java => ViewControllerRegistryTests.java} (59%) create mode 100644 org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupportTests.java 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 index e9b713fc7ea..cb80e95c2f2 100644 --- 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 @@ -21,75 +21,78 @@ import java.util.Map; import javax.servlet.ServletContext; +import org.springframework.util.Assert; import org.springframework.web.HttpRequestHandler; import org.springframework.web.servlet.DispatcherServlet; -import org.springframework.web.servlet.HandlerMapping; +import org.springframework.web.servlet.handler.AbstractHandlerMapping; 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 EnableWebMvc}. - * 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}. + * Configures a request handler for serving static resources by forwarding the request to the Servlet container's + * "default" Servlet. This is indended to be used when the Spring MVC {@link DispatcherServlet} is mapped to "/" + * thus overriding the Servlet container's default handling of static resources. Since this handler is configured + * at the lowest precedence, effectively it allows all other handler mappings to handle the request, and if none + * of them do, this handler can forward it to the "default" Servlet. * * @author Rossen Stoyanchev * @since 3.1 * - * @see ResourceConfigurer + * @see DefaultServletHttpRequestHandler */ public class DefaultServletHandlerConfigurer { - private DefaultServletHttpRequestHandler requestHandler; - private final ServletContext servletContext; + private DefaultServletHttpRequestHandler handler; + + /** + * Create a {@link DefaultServletHandlerConfigurer} instance. + * @param servletContext the ServletContext to use to configure the underlying DefaultServletHttpRequestHandler. + */ public DefaultServletHandlerConfigurer(ServletContext servletContext) { + Assert.notNull(servletContext, "A ServletContext is required to configure default servlet handling"); 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)}. + * Enable forwarding to the "default" Servlet. When this method is used the {@link DefaultServletHttpRequestHandler} + * will try to auto-detect the "default" Servlet name. Alternatively, you can specify the name of the default + * Servlet via {@link #enable(String)}. + * @see DefaultServletHttpRequestHandler */ 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). + * Enable forwarding to the "default" Servlet identified by the given name. + * This is useful when the default Servlet cannot be auto-detected, for example when it has been manually configured. + * @see DefaultServletHttpRequestHandler */ public void enable(String defaultServletName) { - requestHandler = new DefaultServletHttpRequestHandler(); - requestHandler.setDefaultServletName(defaultServletName); - requestHandler.setServletContext(servletContext); + handler = new DefaultServletHttpRequestHandler(); + handler.setDefaultServletName(defaultServletName); + handler.setServletContext(servletContext); } /** - * Return a {@link SimpleUrlHandlerMapping} instance ordered at {@link Integer#MAX_VALUE} containing a - * {@link DefaultServletHttpRequestHandler} mapped to {@code /**}. + * Return a handler mapping instance ordered at {@link Integer#MAX_VALUE} containing the + * {@link DefaultServletHttpRequestHandler} instance mapped to {@code "/**"}; or {@code null} if + * default servlet handling was not been enabled. */ - protected SimpleUrlHandlerMapping getHandlerMapping() { + protected AbstractHandlerMapping getHandlerMapping() { + if (handler == null) { + return null; + } + + Map urlMap = new HashMap(); + urlMap.put("/**", handler); + SimpleUrlHandlerMapping handlerMapping = new SimpleUrlHandlerMapping(); handlerMapping.setOrder(Integer.MAX_VALUE); - handlerMapping.setUrlMap(getUrlMap()); + handlerMapping.setUrlMap(urlMap); return handlerMapping; } - private Map getUrlMap() { - Map urlMap = new HashMap(); - if (requestHandler != null) { - urlMap.put("/**", requestHandler); - } - return urlMap ; - } - } \ No newline at end of file diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.java index 59bc12d4f7e..a459a12700f 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.java @@ -28,11 +28,13 @@ import org.springframework.web.method.support.HandlerMethodReturnValueHandler; import org.springframework.web.servlet.HandlerExceptionResolver; /** - * A variant of {@link WebMvcConfigurationSupport} that delegates to one or more registered {@link WebMvcConfigurer} - * implementations allowing each of them to customize the default Spring MVC configuration. + * A variant of {@link WebMvcConfigurationSupport} that delegates to one or more registered + * {@link WebMvcConfigurer}s allowing each of them to customize the default Spring MVC + * code-based configuration. * - *

This class is automatically imported when @{@link EnableWebMvc} is used on an @{@link Configuration} class. - * In turn it detects all implementations of {@link WebMvcConfigurer} via autowiring and in turn delegates to them. + *

This class is automatically imported when @{@link EnableWebMvc} is used to annotate + * an @{@link Configuration} class. In turn it detects implementations of {@link WebMvcConfigurer} + * via autowiring and delegates to them. * * @see EnableWebMvc * @see WebMvcConfigurer @@ -54,18 +56,18 @@ public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport { } @Override - protected final void configureInterceptors(InterceptorConfigurer configurer) { - configurers.configureInterceptors(configurer); + protected final void addInterceptors(InterceptorRegistry registry) { + configurers.addInterceptors(registry); } @Override - protected final void configureViewControllers(ViewControllerConfigurer configurer) { - configurers.configureViewControllers(configurer); + protected final void addViewControllers(ViewControllerRegistry registry) { + configurers.addViewControllers(registry); } @Override - protected final void configureResourceHandling(ResourceConfigurer configurer) { - configurers.configureResourceHandling(configurer); + protected final void addResourceHandlers(ResourceHandlerRegistry registry) { + configurers.addResourceHandlers(registry); } @Override diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/EnableWebMvc.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/EnableWebMvc.java index 92794b627c1..b6379fcb717 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/EnableWebMvc.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/EnableWebMvc.java @@ -24,9 +24,8 @@ import org.springframework.web.servlet.DispatcherServlet; /** * Enables default Spring MVC configuration and registers Spring MVC infrastructure components expected by the - * {@link DispatcherServlet}. Add this annotation to an application @{@link Configuration} class. It will in - * turn import the @{@link Configuration} class {@link DelegatingWebMvcConfiguration}, which provides default Spring MVC - * configuration. + * {@link DispatcherServlet}. Use this annotation on an @{@link Configuration} class. In turn that will + * import {@link DelegatingWebMvcConfiguration}, which provides default Spring MVC configuration. *

  * @Configuration
  * @EnableWebMvc
@@ -39,9 +38,9 @@ import org.springframework.web.servlet.DispatcherServlet;
  * }
  * 
*

To customize the imported configuration implement {@link WebMvcConfigurer}, or more conveniently extend - * {@link WebMvcConfigurerAdapter} overriding specific methods. Your @{@link Configuration} class and any other - * Spring bean that implements {@link WebMvcConfigurer} will be detected and given an opportunity to customize - * the default Spring MVC configuration through the callback methods on the {@link WebMvcConfigurer} interface. + * {@link WebMvcConfigurerAdapter} overriding specific methods only. Any @{@link Configuration} class that + * implements {@link WebMvcConfigurer} will be detected by {@link DelegatingWebMvcConfiguration} and given + * an opportunity to customize the default Spring MVC code-based configuration. *

  * @Configuration
  * @EnableWebMvc
@@ -52,7 +51,7 @@ import org.springframework.web.servlet.DispatcherServlet;
  * public class MyConfiguration extends WebMvcConfigurerAdapter {
  *
  * 	@Override
- * 	public void registerFormatters(FormatterRegistry formatterRegistry) {
+ * 	public void addFormatters(FormatterRegistry formatterRegistry) {
  * 		formatterRegistry.addConverter(new MyConverter());
  * 	}
  *
@@ -61,7 +60,7 @@ import org.springframework.web.servlet.DispatcherServlet;
  * 		converters.add(new MyHttpMessageConverter());
  * 	}
  *
- * 	...
+ * 	// @Override methods ...
  *
  * }
  * 
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 deleted file mode 100644 index 3ce466121e1..00000000000 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/InterceptorConfigurer.java +++ /dev/null @@ -1,134 +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.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.handler.MappedInterceptor; -import org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter; - -/** - * Helps with configuring an ordered set of Spring MVC interceptors of type {@link HandlerInterceptor} or - * {@link WebRequestInterceptor}. Interceptors can be registered with a set of path patterns. - * - * @author Rossen Stoyanchev - * @since 3.1 - */ -public class InterceptorConfigurer { - - private final List interceptors = new ArrayList(); - - /** - * Add a {@link HandlerInterceptor} that should apply to any request. - */ - public void addInterceptor(HandlerInterceptor interceptor) { - register(interceptor); - } - - /** - * Add a {@link WebRequestInterceptor} that should apply to any request. - */ - public void addInterceptor(WebRequestInterceptor interceptor) { - register(asHandlerInterceptorArray(interceptor)); - } - - /** - * Add {@link HandlerInterceptor}s that should apply to any request. - */ - public void addInterceptors(HandlerInterceptor... interceptors) { - register( interceptors); - } - - /** - * Add {@link WebRequestInterceptor}s that should apply to any request. - */ - public void addInterceptors(WebRequestInterceptor... interceptors) { - register(asHandlerInterceptorArray(interceptors)); - } - - /** - * Add a {@link HandlerInterceptor} with a set of URL path patterns it should apply to. - */ - public void mapInterceptor(String[] pathPatterns, HandlerInterceptor interceptor) { - registerMappedInterceptors(pathPatterns, interceptor); - } - - /** - * Add a {@link WebRequestInterceptor} with a set of URL path patterns it should apply to. - */ - public void mapInterceptor(String[] pathPatterns, WebRequestInterceptor interceptors) { - registerMappedInterceptors(pathPatterns, asHandlerInterceptorArray(interceptors)); - } - - /** - * Add {@link HandlerInterceptor}s with a set of URL path patterns they should apply to. - */ - public void mapInterceptors(String[] pathPatterns, HandlerInterceptor... interceptors) { - registerMappedInterceptors(pathPatterns, interceptors); - } - - /** - * Add {@link WebRequestInterceptor}s with a set of URL path patterns they should apply to. - */ - public void mapInterceptors(String[] pathPatterns, WebRequestInterceptor... interceptors) { - registerMappedInterceptors(pathPatterns, asHandlerInterceptorArray(interceptors)); - } - - private static HandlerInterceptor[] asHandlerInterceptorArray(WebRequestInterceptor...interceptors) { - HandlerInterceptor[] result = new HandlerInterceptor[interceptors.length]; - for (int i = 0; i < result.length; i++) { - result[i] = new WebRequestHandlerInterceptorAdapter(interceptors[i]); - } - return result; - } - - /** - * Stores the given set of {@link HandlerInterceptor}s internally. - * @param interceptors one or more interceptors to be stored - */ - protected void register(HandlerInterceptor...interceptors) { - Assert.notEmpty(interceptors, "At least one interceptor must be provided"); - for (HandlerInterceptor interceptor : interceptors) { - this.interceptors.add(interceptor); - } - } - - /** - * Stores the given set of {@link HandlerInterceptor}s and path patterns internally. - * @param pathPatterns path patterns or {@code null} - * @param interceptors one or more interceptors to be stored - */ - protected void registerMappedInterceptors(String[] pathPatterns, HandlerInterceptor...interceptors) { - Assert.notEmpty(interceptors, "At least one interceptor must be provided"); - Assert.notEmpty(pathPatterns, "Path patterns must be provided"); - for (HandlerInterceptor interceptor : interceptors) { - this.interceptors.add(new MappedInterceptor(pathPatterns, interceptor)); - } - } - - /** - * Returns all registered interceptors. - */ - protected List getInterceptors() { - return interceptors; - } - -} diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/InterceptorRegistration.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/InterceptorRegistration.java new file mode 100644 index 00000000000..6ef77d2ef97 --- /dev/null +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/InterceptorRegistration.java @@ -0,0 +1,68 @@ +/* + * 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.Arrays; +import java.util.List; + +import org.springframework.util.Assert; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.handler.MappedInterceptor; + +/** + * Encapsulates a {@link HandlerInterceptor} and an optional list of URL patterns. + * Results in the creation of a {@link MappedInterceptor} if URL patterns are provided. + * + * @author Rossen Stoyanchev + * @author Keith Donald + * @since 3.1 + */ +public class InterceptorRegistration { + + private final HandlerInterceptor interceptor; + + private final List pathPatterns = new ArrayList(); + + /** + * Creates an {@link InterceptorRegistration} instance. + */ + public InterceptorRegistration(HandlerInterceptor interceptor) { + Assert.notNull(interceptor, "Interceptor is required"); + this.interceptor = interceptor; + } + + /** + * Adds one or more URL patterns to which the registered interceptor should apply to. + * If no URL patterns are provided, the interceptor applies to all paths. + */ + public void addPathPatterns(String... pathPatterns) { + this.pathPatterns.addAll(Arrays.asList(pathPatterns)); + } + + /** + * Returns the underlying interceptor. If URL patterns are provided the returned type is + * {@link MappedInterceptor}; otherwise {@link HandlerInterceptor}. + */ + protected Object getInterceptor() { + if (pathPatterns.isEmpty()) { + return interceptor; + } + return new MappedInterceptor(pathPatterns.toArray(new String[pathPatterns.size()]), interceptor); + } + +} diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/InterceptorRegistry.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/InterceptorRegistry.java new file mode 100644 index 00000000000..7988a67c702 --- /dev/null +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/InterceptorRegistry.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 java.util.ArrayList; +import java.util.List; + +import org.springframework.web.context.request.WebRequestInterceptor; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.handler.WebRequestHandlerInterceptorAdapter; + +/** + * Stores and provides access to a list of interceptors. For each interceptor you can optionally + * specify one or more URL patterns it applies to. + * + * @author Rossen Stoyanchev + * @author Keith Donald + * + * @since 3.1 + */ +public class InterceptorRegistry { + + private final List registrations = new ArrayList(); + + /** + * Adds the provided {@link HandlerInterceptor}. + * @param interceptor the interceptor to add + * @return An {@link InterceptorRegistration} that allows you optionally configure the + * registered interceptor further for example adding URL patterns it should apply to. + */ + public InterceptorRegistration addInterceptor(HandlerInterceptor interceptor) { + InterceptorRegistration registration = new InterceptorRegistration(interceptor); + registrations.add(registration); + return registration; + } + + /** + * Adds the provided {@link WebRequestInterceptor}. + * @param interceptor the interceptor to add + * @return An {@link InterceptorRegistration} that allows you optionally configure the + * registered interceptor further for example adding URL patterns it should apply to. + */ + public InterceptorRegistration addWebRequestInterceptor(WebRequestInterceptor interceptor) { + WebRequestHandlerInterceptorAdapter adapted = new WebRequestHandlerInterceptorAdapter(interceptor); + InterceptorRegistration registration = new InterceptorRegistration(adapted); + registrations.add(registration); + return registration; + } + + /** + * Returns all registered interceptors. + */ + protected List getInterceptors() { + List interceptors = new ArrayList(); + for (InterceptorRegistration registration : registrations) { + interceptors.add(registration.getInterceptor()); + } + return interceptors ; + } + +} 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 deleted file mode 100644 index 576f91f457b..00000000000 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/ResourceConfigurer.java +++ /dev/null @@ -1,197 +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.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 pathPatterns = new ArrayList(); - - private final List locations = new ArrayList(); - - private Integer cachePeriod; - - private int order = Integer.MAX_VALUE -1; - - private final ServletContext servletContext; - - private final ApplicationContext applicationContext; - - public ResourceConfigurer(ApplicationContext applicationContext, ServletContext servletContext) { - Assert.notNull(applicationContext, "ApplicationContext is required"); - this.applicationContext = applicationContext; - this.servletContext = servletContext; - } - - /** - * Add a URL path pattern within the current Servlet context to use for serving static resources - * using the Spring MVC {@link ResourceHttpRequestHandler}, for example {@code "/resources/**"}. - * @return the same {@link ResourceConfigurer} instance for chained method invocation - */ - public ResourceConfigurer addPathMapping(String pathPattern) { - return addPathMappings(pathPattern); - } - - /** - * Add several URL path patterns within the current Servlet context to use for serving static resources - * using the Spring MVC {@link ResourceHttpRequestHandler}, for example {@code "/resources/**"}. - * @return the same {@link ResourceConfigurer} instance for chained method invocation - */ - public ResourceConfigurer addPathMappings(String...pathPatterns) { - for (String path : pathPatterns) { - this.pathPatterns.add(path); - } - return this; - } - - /** - * Add resource location from which to serve static content. The location must point to a valid - * directory.

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 getUrlMap() { - Map urlMap = new LinkedHashMap(); - if (!pathPatterns.isEmpty()) { - ResourceHttpRequestHandler requestHandler = createRequestHandler(); - for (String pathPattern : pathPatterns) { - urlMap.put(pathPattern, requestHandler); - } - } - return urlMap; - } - - /** - * Create a {@link ResourceHttpRequestHandler} instance. - */ - protected ResourceHttpRequestHandler createRequestHandler() { - Assert.isTrue(!CollectionUtils.isEmpty(locations), "Path patterns specified but not resource locations."); - ResourceHttpRequestHandler requestHandler = new ResourceHttpRequestHandler(); - requestHandler.setApplicationContext(applicationContext); - requestHandler.setServletContext(servletContext); - requestHandler.setLocations(locations); - if (cachePeriod != null) { - requestHandler.setCacheSeconds(cachePeriod); - } - return requestHandler; - } - -} \ No newline at end of file diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistration.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistration.java new file mode 100644 index 00000000000..cbad096879b --- /dev/null +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistration.java @@ -0,0 +1,105 @@ +/* + * 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.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; +import org.springframework.web.servlet.resource.ResourceHttpRequestHandler; + +/** + * Encapsulates information required to create a resource handlers. + * + * @author Rossen Stoyanchev + * @author Keith Donald + * + * @since 3.1 + */ +public class ResourceHandlerRegistration { + + private final ResourceLoader resourceLoader; + + private final String[] pathPatterns; + + private final List locations = new ArrayList(); + + private Integer cachePeriod; + + /** + * Create a {@link ResourceHandlerRegistration} instance. + * @param resourceLoader a resource loader for turning a String location into a {@link Resource} + * @param pathPatterns one or more resource URL path patterns + */ + public ResourceHandlerRegistration(ResourceLoader resourceLoader, String... pathPatterns) { + Assert.notEmpty(pathPatterns, "At least one path pattern is required for resource handling."); + this.resourceLoader = resourceLoader; + this.pathPatterns = pathPatterns; + } + + /** + * 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 ResourceHandlerRegistration} instance for chained method invocation + */ + public ResourceHandlerRegistration addResourceLocations(String...resourceLocations) { + for (String location : resourceLocations) { + this.locations.add(resourceLoader.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 ResourceHandlerRegistration} instance for chained method invocation + */ + public ResourceHandlerRegistration setCachePeriod(Integer cachePeriod) { + this.cachePeriod = cachePeriod; + return this; + } + + /** + * Returns the URL path patterns for the resource handler. + */ + protected String[] getPathPatterns() { + return pathPatterns; + } + + /** + * Returns a {@link ResourceHttpRequestHandler} instance. + */ + protected ResourceHttpRequestHandler getRequestHandler() { + Assert.isTrue(!CollectionUtils.isEmpty(locations), "At least one location is required for resource handling."); + ResourceHttpRequestHandler requestHandler = new ResourceHttpRequestHandler(); + requestHandler.setLocations(locations); + if (cachePeriod != null) { + requestHandler.setCacheSeconds(cachePeriod); + } + return requestHandler; + } + +} diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistry.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistry.java new file mode 100644 index 00000000000..e95cc82aaca --- /dev/null +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistry.java @@ -0,0 +1,111 @@ +/* + * 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.util.Assert; +import org.springframework.web.HttpRequestHandler; +import org.springframework.web.servlet.HandlerMapping; +import org.springframework.web.servlet.handler.AbstractHandlerMapping; +import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; +import org.springframework.web.servlet.resource.ResourceHttpRequestHandler; + +/** + * Stores registrations of resource handlers 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 create a resource handler, use {@link #addResourceHandler(String...)} providing the URL path patterns + * for which the handler should be invoked to serve static resources (e.g. {@code "/resources/**"}). + * + *

Then use additional methods on the returned {@link ResourceHandlerRegistration} to add one or more + * locations from which to serve static content from (e.g. {{@code "/"}, + * {@code "classpath:/META-INF/public-web-resources/"}}) or to specify a cache period for served resources. + * + * @author Rossen Stoyanchev + * @since 3.1 + * + * @see DefaultServletHandlerConfigurer + */ +public class ResourceHandlerRegistry { + + private final ServletContext servletContext; + + private final ApplicationContext applicationContext; + + private final List registrations = new ArrayList(); + + private int order = Integer.MAX_VALUE -1; + + public ResourceHandlerRegistry(ApplicationContext applicationContext, ServletContext servletContext) { + Assert.notNull(applicationContext, "ApplicationContext is required"); + this.applicationContext = applicationContext; + this.servletContext = servletContext; + } + + /** + * Add a resource handler for serving static resources based on the specified URL path patterns. + * The handler will be invoked for every incoming request that matches to one of the specified path patterns. + * @return A {@link ResourceHandlerRegistration} to use to further configure the registered resource handler. + */ + public ResourceHandlerRegistration addResourceHandler(String... pathPatterns) { + ResourceHandlerRegistration registration = new ResourceHandlerRegistration(applicationContext, pathPatterns); + registrations.add(registration); + return registration; + } + + /** + * Specify the order to use for resource handling relative to other {@link HandlerMapping}s configured in + * the Spring MVC application context. The default value used is {@code Integer.MAX_VALUE-1}. + */ + public ResourceHandlerRegistry setOrder(int order) { + this.order = order; + return this; + } + + /** + * Return a handler mapping with the mapped resource handlers; or {@code null} in case of no registrations. + */ + protected AbstractHandlerMapping getHandlerMapping() { + if (registrations.isEmpty()) { + return null; + } + + Map urlMap = new LinkedHashMap(); + for (ResourceHandlerRegistration registration : registrations) { + for (String pathPattern : registration.getPathPatterns()) { + ResourceHttpRequestHandler requestHandler = registration.getRequestHandler(); + requestHandler.setServletContext(servletContext); + requestHandler.setApplicationContext(applicationContext); + urlMap.put(pathPattern, requestHandler); + } + } + + SimpleUrlHandlerMapping handlerMapping = new SimpleUrlHandlerMapping(); + handlerMapping.setOrder(order); + handlerMapping.setUrlMap(urlMap); + return handlerMapping; + } + +} \ No newline at end of file diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/ViewControllerConfigurer.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/ViewControllerConfigurer.java deleted file mode 100644 index a5946b63c26..00000000000 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/ViewControllerConfigurer.java +++ /dev/null @@ -1,87 +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.config.annotation; - -import java.util.LinkedHashMap; -import java.util.Map; - -import org.springframework.web.servlet.HandlerMapping; -import org.springframework.web.servlet.RequestToViewNameTranslator; -import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; -import org.springframework.web.servlet.mvc.Controller; -import org.springframework.web.servlet.mvc.ParameterizableViewController; - -/** - * Helps with view controllers. View controllers provide a direct mapping between a URL path and view name. This is - * useful when serving requests that don't require application-specific controller logic and can be forwarded - * directly to a view for rendering. - * - * @author Rossen Stoyanchev - * @since 3.1 - */ -public class ViewControllerConfigurer { - - private final Map urlMap = new LinkedHashMap(); - - private int order = 1; - - /** - * Map the URL path to a view name derived by convention through the DispatcherServlet's - * {@link RequestToViewNameTranslator}. - * @return the same {@link ViewControllerConfigurer} instance for convenient chained method invocation - */ - public ViewControllerConfigurer mapViewNameByConvention(String urlPath) { - return mapViewName(urlPath, null); - } - - /** - * Map the URL path to the specified view name. - * @return the same {@link ViewControllerConfigurer} instance for convenient chained method invocation - */ - public ViewControllerConfigurer mapViewName(String urlPath, String viewName) { - ParameterizableViewController controller = new ParameterizableViewController(); - controller.setViewName(viewName); - urlMap.put(urlPath, controller); - return this; - } - - /** - * Specify the order in which to check view controller path mappings relative to other {@link HandlerMapping} - * instances in the Spring MVC web application context. The default value is 1. - */ - public void setOrder(int order) { - this.order = order; - } - - /** - * Get the order in which to check view controller path mappings relative to other {@link HandlerMapping}s. - */ - public int getOrder() { - return order; - } - - /** - * Return a {@link SimpleUrlHandlerMapping} with URL path to view controllers mappings. - */ - protected SimpleUrlHandlerMapping getHandlerMapping() { - SimpleUrlHandlerMapping handlerMapping = new SimpleUrlHandlerMapping(); - handlerMapping.setOrder(order); - handlerMapping.setUrlMap(urlMap); - return handlerMapping; - } - -} \ No newline at end of file diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/ViewControllerRegistration.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/ViewControllerRegistration.java new file mode 100644 index 00000000000..48700f905d7 --- /dev/null +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/ViewControllerRegistration.java @@ -0,0 +1,70 @@ +/* + * 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 org.springframework.util.Assert; +import org.springframework.web.servlet.RequestToViewNameTranslator; +import org.springframework.web.servlet.mvc.ParameterizableViewController; + +/** + * Encapsulates information required to create a view controller. + * + * @author Rossen Stoyanchev + * @author Keith Donald + * @since 3.1 + */ +public class ViewControllerRegistration { + + private final String urlPath; + + private String viewName; + + /** + * Creates a {@link ViewControllerRegistration} with the given URL path. When a request matches + * to the given URL path this view controller will process it. + */ + public ViewControllerRegistration(String urlPath) { + Assert.notNull(urlPath, "A URL path is required to create a view controller."); + this.urlPath = urlPath; + } + + /** + * Sets the view name to use for this view controller. This field is optional. If not specified the + * view controller will return a {@code null} view name, which will be resolved through the configured + * {@link RequestToViewNameTranslator}. By default that means "/foo/bar" would resolve to "foo/bar". + */ + public void setViewName(String viewName) { + this.viewName = viewName; + } + + /** + * Returns the URL path for the view controller. + */ + protected String getUrlPath() { + return urlPath; + } + + /** + * Returns the view controllers. + */ + protected Object getViewController() { + ParameterizableViewController controller = new ParameterizableViewController(); + controller.setViewName(viewName); + return controller; + } + +} diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/ViewControllerRegistry.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/ViewControllerRegistry.java new file mode 100644 index 00000000000..55d3d457d05 --- /dev/null +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/ViewControllerRegistry.java @@ -0,0 +1,77 @@ +/* + * 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 org.springframework.web.servlet.HandlerMapping; +import org.springframework.web.servlet.handler.AbstractHandlerMapping; +import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; + +/** + * Stores registrations of view controllers. A view controller does nothing more than return a specified + * view name. It saves you from having to write a controller when you want to forward the request straight + * through to a view such as a JSP. + * + * @author Rossen Stoyanchev + * @author Keith Donald + * @since 3.1 + */ +public class ViewControllerRegistry { + + private final List registrations = new ArrayList(); + + private int order = 1; + + public ViewControllerRegistration addViewController(String urlPath) { + ViewControllerRegistration registration = new ViewControllerRegistration(urlPath); + registrations.add(registration); + return registration; + } + + /** + * Specify the order to use for ViewControllers mappings relative to other {@link HandlerMapping}s + * configured in the Spring MVC application context. The default value for view controllers is 1, + * which is 1 higher than the value used for annotated controllers. + */ + public void setOrder(int order) { + this.order = order; + } + + /** + * Returns a handler mapping with the mapped ViewControllers; or {@code null} in case of no registrations. + */ + protected AbstractHandlerMapping getHandlerMapping() { + if (registrations.isEmpty()) { + return null; + } + + Map urlMap = new LinkedHashMap(); + for (ViewControllerRegistration registration : registrations) { + urlMap.put(registration.getUrlPath(), registration.getViewController()); + } + + SimpleUrlHandlerMapping handlerMapping = new SimpleUrlHandlerMapping(); + handlerMapping.setOrder(order); + handlerMapping.setUrlMap(urlMap); + return handlerMapping; + } + +} \ No newline at end of file diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java index 2fe02419360..8da51d8aeb6 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.List; import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; import javax.xml.transform.Source; import org.springframework.beans.BeanUtils; @@ -46,7 +47,6 @@ import org.springframework.http.converter.xml.SourceHttpMessageConverter; import org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter; import org.springframework.util.ClassUtils; import org.springframework.validation.Errors; -import org.springframework.validation.MessageCodesResolver; import org.springframework.validation.Validator; import org.springframework.web.HttpRequestHandler; import org.springframework.web.bind.annotation.ExceptionHandler; @@ -59,10 +59,10 @@ import org.springframework.web.servlet.DispatcherServlet; import org.springframework.web.servlet.HandlerAdapter; import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.HandlerMapping; +import org.springframework.web.servlet.handler.AbstractHandlerMapping; import org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping; import org.springframework.web.servlet.handler.ConversionServiceExposingInterceptor; import org.springframework.web.servlet.handler.HandlerExceptionResolverComposite; -import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; import org.springframework.web.servlet.mvc.Controller; import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter; import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter; @@ -75,27 +75,25 @@ import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolv /** * A base class that provides default configuration for Spring MVC applications by registering Spring MVC * infrastructure components to be detected by the {@link DispatcherServlet}. Typically applications should not - * have to start by extending this class. A much easier place to start is to annotate your @{@link Configuration} - * class with @{@link EnableWebMvc}. See @{@link EnableWebMvc} and {@link WebMvcConfigurer}. + * have to extend this class. A more likely place to start is to annotate an @{@link Configuration} + * class with @{@link EnableWebMvc} (see @{@link EnableWebMvc} and {@link WebMvcConfigurer} for details). * - *

If using @{@link EnableWebMvc} and extending from {@link WebMvcConfigurerAdapter} does not give you the level - * of flexibility you need, consider extending directly from this class instead. Remember to add @{@link Configuration} - * to your subclass and @{@link Bean} to any superclass @{@link Bean} methods you choose to override. A few example - * reasons for extending this class include providing a custom {@link MessageCodesResolver}, changing the order of - * {@link HandlerMapping} instances, plugging in a variant of any of the beans provided by this class, and so on. + *

If using @{@link EnableWebMvc} does not give you all you need, consider extending directly from this + * class. Remember to add @{@link Configuration} to your subclass and @{@link Bean} to any superclass + * @{@link Bean} methods you choose to override. * *

This class registers the following {@link HandlerMapping}s:

*
    *
  • {@link RequestMappingHandlerMapping} ordered at 0 for mapping requests to annotated controller methods. - *
  • {@link SimpleUrlHandlerMapping} ordered at 1 to map URL paths directly to view names. + *
  • {@link HandlerMapping} ordered at 1 to map URL paths directly to view names. *
  • {@link BeanNameUrlHandlerMapping} ordered at 2 to map URL paths to controller bean names. - *
  • {@link SimpleUrlHandlerMapping} ordered at {@code Integer.MAX_VALUE-1} to serve static resource requests. - *
  • {@link SimpleUrlHandlerMapping} ordered at {@code Integer.MAX_VALUE} to forward requests to the default servlet. + *
  • {@link HandlerMapping} ordered at {@code Integer.MAX_VALUE-1} to serve static resource requests. + *
  • {@link HandlerMapping} ordered at {@code Integer.MAX_VALUE} to forward requests to the default servlet. *
* - *

Registers {@link HandlerAdapter}s: + *

Registers these {@link HandlerAdapter}s: *

    - *
  • {@link RequestMappingHandlerAdapter} for processing requests using annotated controller methods. + *
  • {@link RequestMappingHandlerAdapter} for processing requests with annotated controller methods. *
  • {@link HttpRequestHandlerAdapter} for processing requests with {@link HttpRequestHandler}s. *
  • {@link SimpleControllerHandlerAdapter} for processing requests with interface-based {@link Controller}s. *
@@ -107,7 +105,7 @@ import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolv *
  • {@link DefaultHandlerExceptionResolver} for resolving known Spring exception types * * - *

    Registers the following other instances: + *

    Registers these other instances: *

      *
    • {@link FormattingConversionService} for use with annotated controller methods and the spring:eval JSP tag. *
    • {@link Validator} for validating model attributes on annotated controller methods. @@ -143,57 +141,53 @@ public abstract class WebMvcConfigurationSupport implements ApplicationContextAw */ @Bean public RequestMappingHandlerMapping requestMappingHandlerMapping() { - RequestMappingHandlerMapping mapping = new RequestMappingHandlerMapping(); - mapping.setInterceptors(getInterceptors()); - mapping.setOrder(0); - return mapping; + RequestMappingHandlerMapping handlerMapping = new RequestMappingHandlerMapping(); + handlerMapping.setOrder(0); + handlerMapping.setInterceptors(getInterceptors()); + return handlerMapping; } /** * Provides access to the shared handler interceptors used to configure {@link HandlerMapping} instances with. - * This method cannot be overridden, use {@link #configureInterceptors(InterceptorConfigurer)} instead. + * This method cannot be overridden, use {@link #addInterceptors(InterceptorRegistry)} instead. */ protected final Object[] getInterceptors() { if (interceptors == null) { - InterceptorConfigurer configurer = new InterceptorConfigurer(); - configureInterceptors(configurer); - configurer.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService())); - interceptors = configurer.getInterceptors(); + InterceptorRegistry registry = new InterceptorRegistry(); + addInterceptors(registry); + registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService())); + interceptors = registry.getInterceptors(); } return interceptors.toArray(); } /** - * Override this method to configure the Spring MVC interceptors to use. Interceptors allow requests to - * be pre- and post-processed before and after controller invocation. They can be registered to apply - * to all requests or be limited to a set of path patterns. - * @see InterceptorConfigurer + * Override this method to add Spring MVC interceptors for pre/post-processing of controller invocation. + * @see InterceptorRegistry */ - protected void configureInterceptors(InterceptorConfigurer configurer) { + protected void addInterceptors(InterceptorRegistry registry) { } /** - * Returns a {@link SimpleUrlHandlerMapping} ordered at 1 to map URL paths directly to view names. - * To configure view controllers see {@link #configureViewControllers(ViewControllerConfigurer)}. + * Returns a handler mapping ordered at 1 to map URL paths directly to view names. + * To configure view controllers, override {@link #addViewControllers(ViewControllerRegistry)}. */ @Bean - public SimpleUrlHandlerMapping viewControllerHandlerMapping() { - ViewControllerConfigurer configurer = new ViewControllerConfigurer(); - configurer.setOrder(1); - configureViewControllers(configurer); + public HandlerMapping viewControllerHandlerMapping() { + ViewControllerRegistry registry = new ViewControllerRegistry(); + addViewControllers(registry); - SimpleUrlHandlerMapping handlerMapping = configurer.getHandlerMapping(); + AbstractHandlerMapping handlerMapping = registry.getHandlerMapping(); + handlerMapping = handlerMapping != null ? handlerMapping : new EmptyHandlerMapping(); handlerMapping.setInterceptors(getInterceptors()); return handlerMapping; } /** - * Override this method to configure view controllers. View controllers provide a direct mapping between a - * URL path and view name. This is useful when serving requests that don't require application-specific - * controller logic and can be forwarded directly to a view for rendering. - * @see ViewControllerConfigurer + * Override this method to add view controllers. + * @see ViewControllerRegistry */ - protected void configureViewControllers(ViewControllerConfigurer configurer) { + protected void addViewControllers(ViewControllerRegistry registry) { } /** @@ -208,53 +202,50 @@ public abstract class WebMvcConfigurationSupport implements ApplicationContextAw } /** - * Returns a {@link SimpleUrlHandlerMapping} ordered at Integer.MAX_VALUE-1 to serve static resource requests. - * To configure resource handling, see {@link #configureResourceHandling(ResourceConfigurer)}. + * Returns a handler mapping ordered at Integer.MAX_VALUE-1 with mapped resource handlers. + * To configure resource handling, override {@link #addResourceHandlers(ResourceHandlerRegistry)}. */ @Bean - public SimpleUrlHandlerMapping resourceHandlerMapping() { - ResourceConfigurer configurer = new ResourceConfigurer(applicationContext, servletContext); - configurer.setOrder(Integer.MAX_VALUE-1); - configureResourceHandling(configurer); - return configurer.getHandlerMapping(); + public HandlerMapping resourceHandlerMapping() { + ResourceHandlerRegistry registry = new ResourceHandlerRegistry(applicationContext, servletContext); + addResourceHandlers(registry); + AbstractHandlerMapping handlerMapping = registry.getHandlerMapping(); + handlerMapping = handlerMapping != null ? handlerMapping : new EmptyHandlerMapping(); + return handlerMapping; } /** - * Override this method to configure a handler for serving static resources such as images, js, and, css files - * 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. - * @see ResourceConfigurer + * Override this method to add resource handlers for serving static resources. + * @see ResourceHandlerRegistry */ - protected void configureResourceHandling(ResourceConfigurer configurer) { + protected void addResourceHandlers(ResourceHandlerRegistry registry) { } /** - * Returns a {@link SimpleUrlHandlerMapping} ordered at Integer.MAX_VALUE to serve static resources by - * forwarding to the Servlet container's default servlet. To configure default servlet handling see + * Returns a handler mapping ordered at Integer.MAX_VALUE with a mapped default servlet handler. + * To configure "default" Servlet handling, override * {@link #configureDefaultServletHandling(DefaultServletHandlerConfigurer)}. */ @Bean - public SimpleUrlHandlerMapping defaultServletHandlerMapping() { + public HandlerMapping defaultServletHandlerMapping() { DefaultServletHandlerConfigurer configurer = new DefaultServletHandlerConfigurer(servletContext); configureDefaultServletHandling(configurer); - return configurer.getHandlerMapping(); + AbstractHandlerMapping handlerMapping = configurer.getHandlerMapping(); + handlerMapping = handlerMapping != null ? handlerMapping : new EmptyHandlerMapping(); + return handlerMapping; } /** - * Override this method to configure a handler for delegating unhandled requests 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. + * Override this method to configure "default" Servlet handling. * @see DefaultServletHandlerConfigurer */ protected void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { } /** - * Returns a {@link RequestMappingHandlerAdapter} for processing requests using annotated controller methods. - * Also see the following other methods as an alternative to overriding this method: + * Returns a {@link RequestMappingHandlerAdapter} for processing requests through annotated controller methods. + * Consider overriding one of these other more fine-grained methods: *
        - *
      • {@link #initWebBindingInitializer()} for configuring data binding globally. *
      • {@link #addArgumentResolvers(List)} for adding custom argument resolvers. *
      • {@link #addReturnValueHandlers(List)} for adding custom return value handlers. *
      • {@link #configureMessageConverters(List)} for adding custom message converters. @@ -265,7 +256,6 @@ public abstract class WebMvcConfigurationSupport implements ApplicationContextAw ConfigurableWebBindingInitializer webBindingInitializer = new ConfigurableWebBindingInitializer(); webBindingInitializer.setConversionService(mvcConversionService()); webBindingInitializer.setValidator(mvcValidator()); - configureWebBindingInitializer(webBindingInitializer); List argumentResolvers = new ArrayList(); addArgumentResolvers(argumentResolvers); @@ -282,28 +272,21 @@ public abstract class WebMvcConfigurationSupport implements ApplicationContextAw } /** - * Override this method to customize the {@link ConfigurableWebBindingInitializer} the - * {@link RequestMappingHandlerAdapter} is configured with. - */ - protected void configureWebBindingInitializer(ConfigurableWebBindingInitializer webBindingInitializer) { - } - - /** - * Override this method to add custom argument resolvers to use in addition to the ones registered by default - * internally by the {@link RequestMappingHandlerAdapter}. - *

        Generally custom argument resolvers are invoked first. However this excludes default argument resolvers that - * rely on the presence of annotations (e.g. {@code @RequestParameter}, {@code @PathVariable}, etc.). Those - * argument resolvers are not customizable without configuring RequestMappingHandlerAdapter directly. + * Add custom {@link HandlerMethodArgumentResolver}s to use in addition to the ones registered by default. + *

        Custom argument resolvers are invoked before built-in resolvers except for those that rely on the presence + * of annotations (e.g. {@code @RequestParameter}, {@code @PathVariable}, etc.). The latter can be customized + * by configuring the {@link RequestMappingHandlerAdapter} directly. + * @param argumentResolvers the list of custom converters; initially an empty list. */ protected void addArgumentResolvers(List argumentResolvers) { } /** - * Override this method to add custom return value handlers to use in addition to the ones registered by default - * internally by the {@link RequestMappingHandlerAdapter}. - *

        Generally custom return value handlers are invoked first. However this excludes default return value handlers - * that rely on the presence of annotations (e.g. {@code @ResponseBody}, {@code @ModelAttribute}, etc.). Those - * handlers are not customizable without configuring RequestMappingHandlerAdapter directly. + * Add custom {@link HandlerMethodReturnValueHandler}s in addition to the ones registered by default. + *

        Custom return value handlers are invoked before built-in ones except for those that rely on the presence + * of annotations (e.g. {@code @ResponseBody}, {@code @ModelAttribute}, etc.). The latter can be customized + * by configuring the {@link RequestMappingHandlerAdapter} directly. + * @param returnValueHandlers the list of custom handlers; initially an empty list. */ protected void addReturnValueHandlers(List returnValueHandlers) { } @@ -311,8 +294,8 @@ public abstract class WebMvcConfigurationSupport implements ApplicationContextAw /** * Provides access to the shared {@link HttpMessageConverter}s used by the * {@link RequestMappingHandlerAdapter} and the {@link ExceptionHandlerExceptionResolver}. - * This method cannot be extended directly, use {@link #configureMessageConverters(List)} add custom converters. - * For the list of message converters added by default see {@link #addDefaultHttpMessageConverters(List)}. + * This method cannot be overridden. Use {@link #configureMessageConverters(List)} instead. + * Also see {@link #addDefaultHttpMessageConverters(List)} that can be used to add default message converters. */ protected final List> getMessageConverters() { if (messageConverters == null) { @@ -328,16 +311,16 @@ public abstract class WebMvcConfigurationSupport implements ApplicationContextAw /** * Override this method to add custom {@link HttpMessageConverter}s to use with * the {@link RequestMappingHandlerAdapter} and the {@link ExceptionHandlerExceptionResolver}. - * If any converters are added through this method, default converters are added automatically. - * See {@link #addDefaultHttpMessageConverters(List)} for adding default converters to the list. - * @param messageConverters the list to add converters to + * Adding converters to the list turns off the default converters that would otherwise be registered by default. + * Also see {@link #addDefaultHttpMessageConverters(List)} that can be used to add default message converters. + * @param converters a list to add message converters to; initially an empty list. */ protected void configureMessageConverters(List> converters) { } /** - * A method available to subclasses for adding default {@link HttpMessageConverter}s. - * @param messageConverters the list to add converters to + * A method available to subclasses to add default {@link HttpMessageConverter}s. + * @param messageConverters the list to add the default message converters to */ protected final void addDefaultHttpMessageConverters(List> messageConverters) { StringHttpMessageConverter stringConverter = new StringHttpMessageConverter(); @@ -382,8 +365,7 @@ public abstract class WebMvcConfigurationSupport implements ApplicationContextAw /** * Returns {@link Validator} for validating {@code @ModelAttribute} and {@code @RequestBody} arguments of - * annotated controller methods. This method is closed for extension. Use {@link #getValidator()} to - * provide a custom validator. + * annotated controller methods. To configure a custom validation, override {@link #getValidator()}. */ @Bean Validator mvcValidator() { @@ -415,10 +397,7 @@ public abstract class WebMvcConfigurationSupport implements ApplicationContextAw } /** - * Override this method to provide a custom {@link Validator} type. If this method returns {@code null}, by - * a check is made for the presence of a JSR-303 implementation on the classpath - if available a - * {@link org.springframework.validation.beanvalidation.LocalValidatorFactoryBean} instance is created. - * Otherwise if no JSR-303 implementation is detected, a no-op {@link Validator} is returned instead. + * Override this method to provide a custom {@link Validator}. */ protected Validator getValidator() { return null; @@ -442,8 +421,7 @@ public abstract class WebMvcConfigurationSupport implements ApplicationContextAw /** * Returns a {@link HandlerExceptionResolverComposite} that contains a list of exception resolvers. - * This method is closed for extension. Use {@link #configureHandlerExceptionResolvers(List) to - * customize the list of exception resolvers. + * To customize the list of exception resolvers, override {@link #configureHandlerExceptionResolvers(List)}. */ @Bean HandlerExceptionResolver handlerExceptionResolver() throws Exception { @@ -461,10 +439,10 @@ public abstract class WebMvcConfigurationSupport implements ApplicationContextAw } /** - * Override this method to configure the list of {@link HandlerExceptionResolver}s to use for handling - * unresolved controller exceptions. If any exception resolvers are added through this method, default - * exception resolvers are not added automatically. For the list of exception resolvers added by - * default see {@link #addDefaultHandlerExceptionResolvers(List)}. + * Override this method to configure the list of {@link HandlerExceptionResolver}s to use. + * Adding resolvers to the list turns off the default resolvers that would otherwise be registered by default. + * Also see {@link #addDefaultHandlerExceptionResolvers(List)} that can be used to add the default exception resolvers. + * @param exceptionResolvers a list to add exception resolvers to; initially an empty list. */ protected void configureHandlerExceptionResolvers(List exceptionResolvers) { } @@ -487,5 +465,13 @@ public abstract class WebMvcConfigurationSupport implements ApplicationContextAw exceptionResolvers.add(new ResponseStatusExceptionResolver()); exceptionResolvers.add(new DefaultHandlerExceptionResolver()); } + + private final static class EmptyHandlerMapping extends AbstractHandlerMapping { + + @Override + protected Object getHandlerInternal(HttpServletRequest request) throws Exception { + return null; + } + } } diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurer.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurer.java index 8e1e9b2b3bd..665b9325df8 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurer.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurer.java @@ -24,23 +24,21 @@ import org.springframework.format.FormatterRegistry; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.validation.Validator; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.context.request.WebRequestInterceptor; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.HandlerMethodReturnValueHandler; import org.springframework.web.servlet.DispatcherServlet; import org.springframework.web.servlet.HandlerExceptionResolver; -import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; import com.sun.corba.se.impl.presentation.rmi.ExceptionHandler; /** - * Defines configuration callback methods for customizing the default Spring MVC configuration enabled through the - * use of @{@link EnableWebMvc}. + * Defines configuration callback methods for customizing the default Spring MVC code-based configuration enabled + * through @{@link EnableWebMvc}. * *

        Classes annotated with @{@link EnableWebMvc} can implement this interface in order to be called back and - * given a chance to customize the default configuration. The most convenient way to implement this interface is - * by extending from {@link WebMvcConfigurerAdapter}, which provides empty method implementations and allows - * overriding only the callback methods you're interested in. + * given a chance to customize the default configuration. The most convenient way to implement this interface + * is to extend {@link WebMvcConfigurerAdapter}, which provides empty method implementations. * * @author Rossen Stoyanchev * @author Keith Donald @@ -56,9 +54,9 @@ public interface WebMvcConfigurer { /** * Configure the list of {@link HttpMessageConverter}s to use when resolving method arguments or handling - * return values in @{@link RequestMapping} and @{@link ExceptionHandler} methods. - * Specifying custom converters overrides the converters registered by default. - * @param converters a list to add message converters to + * return values in @{@link RequestMapping} and @{@link ExceptionHandler} methods. + * Adding converters to the list turns off the default converters that would otherwise be registered by default. + * @param converters a list to add message converters to; initially an empty list. */ void configureMessageConverters(List> converters); @@ -71,58 +69,56 @@ public interface WebMvcConfigurer { /** * Add custom {@link HandlerMethodArgumentResolver}s to use in addition to the ones registered by default. - *

        Generally custom argument resolvers are invoked first. However this excludes default argument resolvers that - * rely on the presence of annotations (e.g. {@code @RequestParameter}, {@code @PathVariable}, etc.). Those - * argument resolvers are not customizable without configuring RequestMappingHandlerAdapter directly. - * @param argumentResolvers the list of custom converters, initially empty + *

        Custom argument resolvers are invoked before built-in resolvers except for those that rely on the presence + * of annotations (e.g. {@code @RequestParameter}, {@code @PathVariable}, etc.). The latter can be customized + * by configuring the {@link RequestMappingHandlerAdapter} directly. + * @param argumentResolvers the list of custom converters; initially an empty list. */ void addArgumentResolvers(List argumentResolvers); /** - * Add custom {@link HandlerMethodReturnValueHandler}s to in addition to the ones registered by default. - *

        Generally custom return value handlers are invoked first. However this excludes default return value handlers - * that rely on the presence of annotations (e.g. {@code @ResponseBody}, {@code @ModelAttribute}, etc.). Those - * handlers are not customizable without configuring RequestMappingHandlerAdapter directly. - * @param returnValueHandlers the list of custom handlers, initially empty + * Add custom {@link HandlerMethodReturnValueHandler}s in addition to the ones registered by default. + *

        Custom return value handlers are invoked before built-in ones except for those that rely on the presence + * of annotations (e.g. {@code @ResponseBody}, {@code @ModelAttribute}, etc.). The latter can be customized + * by configuring the {@link RequestMappingHandlerAdapter} directly. + * @param returnValueHandlers the list of custom handlers; initially an empty list. */ void addReturnValueHandlers(List returnValueHandlers); /** * Configure the list of {@link HandlerExceptionResolver}s to use for handling unresolved controller exceptions. - * Specifying exception resolvers overrides the ones registered by default. - * @param exceptionResolvers a list to add exception resolvers to + * Adding resolvers to the list turns off the default resolvers that would otherwise be registered by default. + * @param exceptionResolvers a list to add exception resolvers to; initially an empty list. */ void configureHandlerExceptionResolvers(List exceptionResolvers); /** - * Configure the Spring MVC interceptors to use. Interceptors allow requests to be pre- and post-processed - * before and after controller invocation. They can be registered to apply to all requests or be limited - * to a set of path patterns. - * @see InterceptorConfigurer + * Add Spring MVC lifecycle interceptors for pre- and post-processing of controller method invocations. + * Interceptors can be registered to apply to all requests or to a set of URL path patterns. + * @see InterceptorRegistry */ - void configureInterceptors(InterceptorConfigurer configurer); + void addInterceptors(InterceptorRegistry registry); /** - * Configure view controllers. View controllers provide a direct mapping between a URL path and view name. - * This is useful when serving requests that don't require application-specific controller logic and can - * be forwarded directly to a view for rendering. - * @see ViewControllerConfigurer + * Add view controllers to create a direct mapping between a URL path and view name. This is useful when + * you just want to forward the request to a view such as a JSP without the need for controller logic. + * @see ViewControllerRegistry */ - void configureViewControllers(ViewControllerConfigurer configurer); + void addViewControllers(ViewControllerRegistry registry); /** - * Configure a handler for serving static resources such as images, js, and, css files 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. - * @see ResourceConfigurer + * Add resource handlers to use to serve static resources such as images, js, and, css files through + * the Spring MVC {@link DispatcherServlet} including the setting of 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. + * @see ResourceHandlerRegistry */ - void configureResourceHandling(ResourceConfigurer configurer); + void addResourceHandlers(ResourceHandlerRegistry registry); /** - * Configure a handler for delegating unhandled requests 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. + * Configure a handler for delegating unhandled requests by forwarding to the Servlet container's "default" + * servlet. The use case for this is when the {@link DispatcherServlet} is mapped to "/" thus overriding + * the Servlet container's default handling of static resources. * @see DefaultServletHandlerConfigurer */ void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer); diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurerAdapter.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurerAdapter.java index d3ef44d8c51..6f941eca5af 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurerAdapter.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurerAdapter.java @@ -26,8 +26,7 @@ import org.springframework.web.method.support.HandlerMethodReturnValueHandler; import org.springframework.web.servlet.HandlerExceptionResolver; /** - * An abstract class with empty method implementations of {@link WebMvcConfigurer}. - * Subclasses can override only the methods they need. + * An convenient base class with empty method implementations of {@link WebMvcConfigurer}. * * @author Rossen Stoyanchev * @since 3.1 @@ -81,21 +80,21 @@ public abstract class WebMvcConfigurerAdapter implements WebMvcConfigurer { * {@inheritDoc} *

        This implementation is empty. */ - public void configureInterceptors(InterceptorConfigurer configurer) { + public void addInterceptors(InterceptorRegistry registry) { } /** * {@inheritDoc} *

        This implementation is empty. */ - public void configureViewControllers(ViewControllerConfigurer configurer) { + public void addViewControllers(ViewControllerRegistry registry) { } /** * {@inheritDoc} *

        This implementation is empty. */ - public void configureResourceHandling(ResourceConfigurer configurer) { + public void addResourceHandlers(ResourceHandlerRegistry registry) { } /** diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurerComposite.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurerComposite.java index 5a602174275..1c0e7494e9a 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurerComposite.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurerComposite.java @@ -74,21 +74,21 @@ class WebMvcConfigurerComposite implements WebMvcConfigurer { } } - public void configureInterceptors(InterceptorConfigurer configurer) { + public void addInterceptors(InterceptorRegistry registry) { for (WebMvcConfigurer delegate : delegates) { - delegate.configureInterceptors(configurer); + delegate.addInterceptors(registry); } } - public void configureViewControllers(ViewControllerConfigurer configurer) { + public void addViewControllers(ViewControllerRegistry registry) { for (WebMvcConfigurer delegate : delegates) { - delegate.configureViewControllers(configurer); + delegate.addViewControllers(registry); } } - public void configureResourceHandling(ResourceConfigurer configurer) { + public void addResourceHandlers(ResourceHandlerRegistry registry) { for (WebMvcConfigurer delegate : delegates) { - delegate.configureResourceHandling(configurer); + delegate.addResourceHandlers(registry); } } diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParserTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParserTests.java index 72531cfa53e..c9c586240f7 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParserTests.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParserTests.java @@ -62,7 +62,7 @@ public class AnnotationDrivenBeanDefinitionParserTests { loadBeanDefinitions("mvc-config-message-codes-resolver.xml"); RequestMappingHandlerAdapter adapter = appContext.getBean(RequestMappingHandlerAdapter.class); assertNotNull(adapter); - Object initializer = new DirectFieldAccessor(adapter).getPropertyValue("webBindingInitializer"); + Object initializer = adapter.getWebBindingInitializer(); assertNotNull(initializer); MessageCodesResolver resolver = ((ConfigurableWebBindingInitializer) initializer).getMessageCodesResolver(); assertNotNull(resolver); 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 index 874ef655d99..8d00d78dc90 100644 --- 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 @@ -18,7 +18,7 @@ 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 static org.junit.Assert.assertNull; import javax.servlet.RequestDispatcher; @@ -53,13 +53,14 @@ public class DefaultServletHandlerConfigurerTests { @Test public void notEnabled() { - assertTrue(configurer.getHandlerMapping().getUrlMap().isEmpty()); + assertNull(configurer.getHandlerMapping()); } @Test public void enable() throws Exception { configurer.enable(); - SimpleUrlHandlerMapping handlerMapping = configurer.getHandlerMapping(); + SimpleUrlHandlerMapping getHandlerMapping = getHandlerMapping(); + SimpleUrlHandlerMapping handlerMapping = getHandlerMapping; DefaultServletHttpRequestHandler handler = (DefaultServletHttpRequestHandler) handlerMapping.getUrlMap().get("/**"); assertNotNull(handler); @@ -75,7 +76,7 @@ public class DefaultServletHandlerConfigurerTests { @Test public void enableWithServletName() throws Exception { configurer.enable("defaultServlet"); - SimpleUrlHandlerMapping handlerMapping = configurer.getHandlerMapping(); + SimpleUrlHandlerMapping handlerMapping = getHandlerMapping(); DefaultServletHttpRequestHandler handler = (DefaultServletHttpRequestHandler) handlerMapping.getUrlMap().get("/**"); assertNotNull(handler); @@ -99,4 +100,8 @@ public class DefaultServletHandlerConfigurerTests { } } + private SimpleUrlHandlerMapping getHandlerMapping() { + return (SimpleUrlHandlerMapping) configurer.getHandlerMapping(); + } + } diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfigurationTests.java similarity index 73% rename from org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationTests.java rename to org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfigurationTests.java index 130342b24f4..2ce7795f76d 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationTests.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfigurationTests.java @@ -18,11 +18,9 @@ package org.springframework.web.servlet.config.annotation; import static org.easymock.EasyMock.capture; import static org.easymock.EasyMock.expect; -import static org.easymock.EasyMock.isA; 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; @@ -30,8 +28,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import javax.servlet.http.HttpServletRequest; - import org.easymock.Capture; import org.easymock.EasyMock; import org.junit.Before; @@ -39,29 +35,23 @@ import org.junit.Test; import org.springframework.format.support.FormattingConversionService; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.StringHttpMessageConverter; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.stereotype.Controller; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; -import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.support.ConfigurableWebBindingInitializer; -import org.springframework.web.context.support.StaticWebApplicationContext; 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.HandlerExecutionChain; import org.springframework.web.servlet.handler.HandlerExceptionResolverComposite; 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.RequestMappingHandlerAdapter; -import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver; /** - * A test fixture for WebMvcConfiguration tests. + * A test fixture for {@link DelegatingWebMvcConfiguration} tests. * * @author Rossen Stoyanchev */ -public class WebMvcConfigurationTests { +public class DelegatingWebMvcConfigurationTests { private DelegatingWebMvcConfiguration mvcConfiguration; @@ -74,7 +64,7 @@ public class WebMvcConfigurationTests { } @Test - public void annotationHandlerAdapter() throws Exception { + public void requestMappingHandlerAdapter() throws Exception { Capture>> converters = new Capture>>(); Capture conversionService = new Capture(); Capture> resolvers = new Capture>(); @@ -96,7 +86,6 @@ public class WebMvcConfigurationTests { assertEquals(0, resolvers.getValue().size()); assertEquals(0, handlers.getValue().size()); - assertTrue(converters.getValue().size() > 0); assertEquals(converters.getValue(), adapter.getMessageConverters()); verify(configurer); @@ -104,9 +93,6 @@ public class WebMvcConfigurationTests { @Test public void configureMessageConverters() { - RequestMappingHandlerAdapter adapter = mvcConfiguration.requestMappingHandlerAdapter(); - assertTrue("There should be at least two default converters ", adapter.getMessageConverters().size() > 1); - List configurers = new ArrayList(); configurers.add(new WebMvcConfigurerAdapter() { @Override @@ -117,7 +103,7 @@ public class WebMvcConfigurationTests { mvcConfiguration = new DelegatingWebMvcConfiguration(); mvcConfiguration.setConfigurers(configurers); - adapter = mvcConfiguration.requestMappingHandlerAdapter(); + RequestMappingHandlerAdapter adapter = mvcConfiguration.requestMappingHandlerAdapter(); assertEquals("Only one custom converter should be registered", 1, adapter.getMessageConverters().size()); } @@ -132,17 +118,6 @@ public class WebMvcConfigurationTests { verify(configurer); } - @Test - public void configureValidator() { - expect(configurer.getValidator()).andReturn(null); - replay(configurer); - - mvcConfiguration.setConfigurers(Arrays.asList(configurer)); - mvcConfiguration.mvcValidator(); - - verify(configurer); - } - @Test public void handlerExceptionResolver() throws Exception { Capture>> converters = new Capture>>(); @@ -166,11 +141,6 @@ public class WebMvcConfigurationTests { @Test public void configureExceptionResolvers() throws Exception { - HandlerExceptionResolverComposite composite; - - composite = (HandlerExceptionResolverComposite) mvcConfiguration.handlerExceptionResolver(); - assertTrue("Expected more than one exception resolver by default", composite.getExceptionResolvers().size() > 1); - List configurers = new ArrayList(); configurers.add(new WebMvcConfigurerAdapter() { @Override @@ -180,32 +150,9 @@ public class WebMvcConfigurationTests { }); mvcConfiguration.setConfigurers(configurers); - composite = (HandlerExceptionResolverComposite) mvcConfiguration.handlerExceptionResolver(); + HandlerExceptionResolverComposite composite = + (HandlerExceptionResolverComposite) mvcConfiguration.handlerExceptionResolver(); assertEquals("Only one custom converter is expected", 1, composite.getExceptionResolvers().size()); } - @Test - public void configureInterceptors() throws Exception { - HttpServletRequest request = new MockHttpServletRequest("GET", "/"); - - StaticWebApplicationContext context = new StaticWebApplicationContext(); - context.registerSingleton("controller", TestHandler.class); - - RequestMappingHandlerMapping hm = mvcConfiguration.requestMappingHandlerMapping(); - hm.setApplicationContext(context); - HandlerExecutionChain chain = hm.getHandler(request); - assertNotNull("No chain returned", chain); - assertNotNull("Expected at least one default converter", chain.getInterceptors()); - } - - @Controller - private static class TestHandler { - - @SuppressWarnings("unused") - @RequestMapping("/") - public void handle() { - } - - } - } 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/InterceptorRegistryTests.java similarity index 75% rename from org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/InterceptorConfigurerTests.java rename to org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/InterceptorRegistryTests.java index 1f1534f6ea1..a0c8fa442fd 100644 --- 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/InterceptorRegistryTests.java @@ -40,14 +40,14 @@ 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 + * Test fixture with a {@link InterceptorRegistry}, two {@link HandlerInterceptor}s and two * {@link WebRequestInterceptor}s. * * @author Rossen Stoyanchev */ -public class InterceptorConfigurerTests { +public class InterceptorRegistryTests { - private InterceptorConfigurer configurer; + private InterceptorRegistry registry; private final HandlerInterceptor interceptor1 = new LocaleChangeInterceptor(); @@ -63,54 +63,50 @@ public class InterceptorConfigurerTests { @Before public void setUp() { - configurer = new InterceptorConfigurer(); + registry = new InterceptorRegistry(); webRequestInterceptor1 = new TestWebRequestInterceptor(); webRequestInterceptor2 = new TestWebRequestInterceptor(); } @Test public void addInterceptor() { - configurer.addInterceptor(interceptor1); + registry.addInterceptor(interceptor1); List interceptors = getInterceptorsForPath(null); + assertEquals(Arrays.asList(interceptor1), interceptors); } @Test - public void addInterceptors() { - configurer.addInterceptors(interceptor1, interceptor2); + public void addTwoInterceptors() { + registry.addInterceptor(interceptor1); + registry.addInterceptor(interceptor2); List interceptors = getInterceptorsForPath(null); + assertEquals(Arrays.asList(interceptor1, interceptor2), interceptors); } @Test - public void mapInterceptor() { - configurer.mapInterceptor(new String[] {"/path1"}, interceptor1); - configurer.mapInterceptor(new String[] {"/path2"}, interceptor2); - + public void addInterceptorsWithUrlPatterns() { + registry.addInterceptor(interceptor1).addPathPatterns("/path1"); + registry.addInterceptor(interceptor2).addPathPatterns("/path2"); + assertEquals(Arrays.asList(interceptor1), getInterceptorsForPath("/path1")); assertEquals(Arrays.asList(interceptor2), getInterceptorsForPath("/path2")); } - @Test - public void mapInterceptors() { - configurer.mapInterceptors(new String[] {"/path1"}, interceptor1, interceptor2); - - assertEquals(Arrays.asList(interceptor1, interceptor2), getInterceptorsForPath("/path1")); - assertEquals(Arrays.asList(), getInterceptorsForPath("/path2")); - } - @Test public void addWebRequestInterceptor() throws Exception { - configurer.addInterceptor(webRequestInterceptor1); + registry.addWebRequestInterceptor(webRequestInterceptor1); List interceptors = getInterceptorsForPath(null); - + assertEquals(1, interceptors.size()); verifyAdaptedInterceptor(interceptors.get(0), webRequestInterceptor1); } @Test public void addWebRequestInterceptors() throws Exception { - configurer.addInterceptors(webRequestInterceptor1, webRequestInterceptor2); + registry.addWebRequestInterceptor(webRequestInterceptor1); + registry.addWebRequestInterceptor(webRequestInterceptor2); List interceptors = getInterceptorsForPath(null); assertEquals(2, interceptors.size()); @@ -119,9 +115,9 @@ public class InterceptorConfigurerTests { } @Test - public void mapWebRequestInterceptor() throws Exception { - configurer.mapInterceptor(new String[] {"/path1"}, webRequestInterceptor1); - configurer.mapInterceptor(new String[] {"/path2"}, webRequestInterceptor2); + public void addWebRequestInterceptorsWithUrlPatterns() throws Exception { + registry.addWebRequestInterceptor(webRequestInterceptor1).addPathPatterns("/path1"); + registry.addWebRequestInterceptor(webRequestInterceptor2).addPathPatterns("/path2"); List interceptors = getInterceptorsForPath("/path1"); assertEquals(1, interceptors.size()); @@ -132,22 +128,10 @@ public class InterceptorConfigurerTests { verifyAdaptedInterceptor(interceptors.get(0), webRequestInterceptor2); } - @Test - public void mapWebRequestInterceptor2() throws Exception { - configurer.mapInterceptors(new String[] {"/path1"}, webRequestInterceptor1, webRequestInterceptor2); - - List interceptors = getInterceptorsForPath("/path1"); - assertEquals(2, interceptors.size()); - verifyAdaptedInterceptor(interceptors.get(0), webRequestInterceptor1); - verifyAdaptedInterceptor(interceptors.get(1), webRequestInterceptor2); - - assertEquals(0, getInterceptorsForPath("/path2").size()); - } - private List getInterceptorsForPath(String lookupPath) { PathMatcher pathMatcher = new AntPathMatcher(); List result = new ArrayList(); - for (Object i : configurer.getInterceptors()) { + for (Object i : registry.getInterceptors()) { if (i instanceof MappedInterceptor) { MappedInterceptor mappedInterceptor = (MappedInterceptor) i; if (mappedInterceptor.matches(lookupPath, pathMatcher)) { 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/ResourceHandlerRegistryTests.java similarity index 55% rename from org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/ResourceConfigurerTests.java rename to org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/ResourceHandlerRegistryTests.java index ba8d59488a7..145e1b7a6c9 100644 --- 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/ResourceHandlerRegistryTests.java @@ -17,7 +17,7 @@ package org.springframework.web.servlet.config.annotation; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertNull; import org.junit.Before; import org.junit.Test; @@ -26,32 +26,34 @@ 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.handler.SimpleUrlHandlerMapping; import org.springframework.web.servlet.resource.ResourceHttpRequestHandler; /** - * Test fixture with a {@link ResourceConfigurer}. + * Test fixture with a {@link ResourceHandlerRegistry}. * * @author Rossen Stoyanchev */ -public class ResourceConfigurerTests { +public class ResourceHandlerRegistryTests { - private ResourceConfigurer configurer; + private ResourceHandlerRegistry registry; + + private ResourceHandlerRegistration registration; 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/"); - + registry = new ResourceHandlerRegistry(new GenericWebApplicationContext(), new MockServletContext()); + registration = registry.addResourceHandler("/resources/**"); + registration.addResourceLocations("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()); + public void noResourceHandlers() throws Exception { + registry = new ResourceHandlerRegistry(new GenericWebApplicationContext(), new MockServletContext()); + assertNull(registry.getHandlerMapping()); } @Test @@ -60,7 +62,7 @@ public class ResourceConfigurerTests { request.setMethod("GET"); request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "/testStylesheet.css"); - ResourceHttpRequestHandler handler = getResourceHandler("/resources/**"); + ResourceHttpRequestHandler handler = getHandler("/resources/**"); handler.handleRequest(request, response); assertEquals("test stylesheet content", response.getContentAsString()); @@ -68,22 +70,23 @@ public class ResourceConfigurerTests { @Test public void cachePeriod() { - assertEquals(-1, getResourceHandler("/resources/**").getCacheSeconds()); + assertEquals(-1, getHandler("/resources/**").getCacheSeconds()); - configurer.setCachePeriod(0); - assertEquals(0, getResourceHandler("/resources/**").getCacheSeconds()); + registration.setCachePeriod(0); + assertEquals(0, getHandler("/resources/**").getCacheSeconds()); } @Test public void order() { - assertEquals(Integer.MAX_VALUE -1, configurer.getHandlerMapping().getOrder()); + assertEquals(Integer.MAX_VALUE -1, registry.getHandlerMapping().getOrder()); - configurer.setOrder(0); - assertEquals(0, configurer.getHandlerMapping().getOrder()); + registry.setOrder(0); + assertEquals(0, registry.getHandlerMapping().getOrder()); } - private ResourceHttpRequestHandler getResourceHandler(String pathPattern) { - return (ResourceHttpRequestHandler) configurer.getHandlerMapping().getUrlMap().get(pathPattern); + private ResourceHttpRequestHandler getHandler(String pathPattern) { + SimpleUrlHandlerMapping handlerMapping = (SimpleUrlHandlerMapping) registry.getHandlerMapping(); + return (ResourceHttpRequestHandler) handlerMapping.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/ViewControllerRegistryTests.java similarity index 59% rename from org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/ViewControllerConfigurerTests.java rename to org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/ViewControllerRegistryTests.java index f0edd47decf..b6e3ad28385 100644 --- 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/ViewControllerRegistryTests.java @@ -16,7 +16,9 @@ package org.springframework.web.servlet.config.annotation; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import java.util.Map; @@ -26,50 +28,55 @@ import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; import org.springframework.web.servlet.mvc.ParameterizableViewController; /** - * Test fixture with a {@link ViewControllerConfigurer}. + * Test fixture with a {@link ViewControllerRegistry}. * * @author Rossen Stoyanchev */ -public class ViewControllerConfigurerTests { +public class ViewControllerRegistryTests { - private ViewControllerConfigurer configurer; + private ViewControllerRegistry registry; @Before public void setUp() { - configurer = new ViewControllerConfigurer(); + registry = new ViewControllerRegistry(); } @Test - public void noMappings() throws Exception { - Map urlMap = configurer.getHandlerMapping().getUrlMap(); - assertTrue(urlMap.isEmpty()); + public void noViewControllers() throws Exception { + assertNull(registry.getHandlerMapping()); } @Test - public void mapViewName() { - configurer.mapViewName("/path", "viewName"); - Map urlMap = configurer.getHandlerMapping().getUrlMap(); - ParameterizableViewController controller = (ParameterizableViewController) urlMap.get("/path"); - assertNotNull(controller); - assertEquals("viewName", controller.getViewName()); - } - - @Test - public void mapViewNameByConvention() { - configurer.mapViewNameByConvention("/path"); - Map urlMap = configurer.getHandlerMapping().getUrlMap(); + public void addViewController() { + registry.addViewController("/path"); + Map urlMap = getHandlerMapping().getUrlMap(); ParameterizableViewController controller = (ParameterizableViewController) urlMap.get("/path"); assertNotNull(controller); assertNull(controller.getViewName()); } + @Test + public void addViewControllerWithViewName() { + registry.addViewController("/path").setViewName("viewName"); + Map urlMap = getHandlerMapping().getUrlMap(); + ParameterizableViewController controller = (ParameterizableViewController) urlMap.get("/path"); + assertNotNull(controller); + assertEquals("viewName", controller.getViewName()); + } + @Test public void order() { - SimpleUrlHandlerMapping handlerMapping = configurer.getHandlerMapping(); + registry.addViewController("/path"); + SimpleUrlHandlerMapping handlerMapping = getHandlerMapping(); assertEquals(1, handlerMapping.getOrder()); - configurer.setOrder(2); - handlerMapping = configurer.getHandlerMapping(); + registry.setOrder(2); + handlerMapping = getHandlerMapping(); assertEquals(2, handlerMapping.getOrder()); } + + private SimpleUrlHandlerMapping getHandlerMapping() { + return (SimpleUrlHandlerMapping) registry.getHandlerMapping(); + } + } diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupportTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupportTests.java new file mode 100644 index 00000000000..08ae16db95d --- /dev/null +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupportTests.java @@ -0,0 +1,315 @@ +/* + * 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 java.util.ArrayList; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.beans.DirectFieldAccessor; +import org.springframework.beans.TestBean; +import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.converter.Converter; +import org.springframework.core.io.FileSystemResourceLoader; +import org.springframework.format.FormatterRegistry; +import org.springframework.format.support.FormattingConversionService; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.json.MappingJacksonHttpMessageConverter; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockServletContext; +import org.springframework.stereotype.Controller; +import org.springframework.validation.BeanPropertyBindingResult; +import org.springframework.validation.Errors; +import org.springframework.validation.Validator; +import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.support.ConfigurableWebBindingInitializer; +import org.springframework.web.context.support.StaticWebApplicationContext; +import org.springframework.web.method.annotation.support.ModelAttributeMethodProcessor; +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.HandlerExecutionChain; +import org.springframework.web.servlet.handler.AbstractHandlerMapping; +import org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping; +import org.springframework.web.servlet.handler.ConversionServiceExposingInterceptor; +import org.springframework.web.servlet.handler.HandlerExceptionResolverComposite; +import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver; +import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; +import org.springframework.web.servlet.mvc.method.annotation.support.DefaultMethodReturnValueHandler; + +/** + * A test fixture for {@link WebMvcConfigurationSupport}. + * + * @author Rossen Stoyanchev + */ +public class WebMvcConfigurationSupportTests { + + private TestWebMvcConfiguration mvcConfiguration; + + @Before + public void setUp() { + mvcConfiguration = new TestWebMvcConfiguration(); + } + + @Test + public void requestMappingHandlerMapping() throws Exception { + StaticWebApplicationContext cxt = new StaticWebApplicationContext(); + cxt.registerSingleton("controller", TestController.class); + + RequestMappingHandlerMapping handlerMapping = mvcConfiguration.requestMappingHandlerMapping(); + assertEquals(0, handlerMapping.getOrder()); + + handlerMapping.setApplicationContext(cxt); + HandlerExecutionChain chain = handlerMapping.getHandler(new MockHttpServletRequest("GET", "/")); + assertNotNull(chain.getInterceptors()); + assertEquals(ConversionServiceExposingInterceptor.class, chain.getInterceptors()[0].getClass()); + } + + @Test + public void emptyViewControllerHandlerMapping() { + AbstractHandlerMapping handlerMapping = (AbstractHandlerMapping) mvcConfiguration.viewControllerHandlerMapping(); + assertNotNull(handlerMapping); + assertEquals(Integer.MAX_VALUE, handlerMapping.getOrder()); + assertTrue(handlerMapping.getClass().getName().endsWith("EmptyHandlerMapping")); + } + + @Test + public void beanNameHandlerMapping() throws Exception { + StaticWebApplicationContext cxt = new StaticWebApplicationContext(); + cxt.registerSingleton("/controller", TestController.class); + + HttpServletRequest request = new MockHttpServletRequest("GET", "/controller"); + + BeanNameUrlHandlerMapping handlerMapping = mvcConfiguration.beanNameHandlerMapping(); + assertEquals(2, handlerMapping.getOrder()); + + handlerMapping.setApplicationContext(cxt); + HandlerExecutionChain chain = handlerMapping.getHandler(request); + assertNotNull(chain.getInterceptors()); + assertEquals(2, chain.getInterceptors().length); + assertEquals(ConversionServiceExposingInterceptor.class, chain.getInterceptors()[1].getClass()); + } + + @Test + public void emptyResourceHandlerMapping() { + mvcConfiguration.setApplicationContext(new StaticWebApplicationContext()); + AbstractHandlerMapping handlerMapping = (AbstractHandlerMapping) mvcConfiguration.resourceHandlerMapping(); + assertNotNull(handlerMapping); + assertEquals(Integer.MAX_VALUE, handlerMapping.getOrder()); + assertTrue(handlerMapping.getClass().getName().endsWith("EmptyHandlerMapping")); + } + + @Test + public void emptyDefaultServletHandlerMapping() { + mvcConfiguration.setServletContext(new MockServletContext()); + AbstractHandlerMapping handlerMapping = (AbstractHandlerMapping) mvcConfiguration.defaultServletHandlerMapping(); + assertNotNull(handlerMapping); + assertEquals(Integer.MAX_VALUE, handlerMapping.getOrder()); + assertTrue(handlerMapping.getClass().getName().endsWith("EmptyHandlerMapping")); + } + + @Test + public void requestMappingHandlerAdapter() throws Exception { + RequestMappingHandlerAdapter adapter = mvcConfiguration.requestMappingHandlerAdapter(); + + List> expectedConverters = new ArrayList>(); + mvcConfiguration.addDefaultHttpMessageConverters(expectedConverters); + assertEquals(expectedConverters.size(), adapter.getMessageConverters().size()); + + ConfigurableWebBindingInitializer initializer = (ConfigurableWebBindingInitializer) adapter.getWebBindingInitializer(); + assertNotNull(initializer); + + ConversionService conversionService = initializer.getConversionService(); + assertNotNull(conversionService); + assertTrue(conversionService instanceof FormattingConversionService); + + Validator validator = initializer.getValidator(); + assertNotNull(validator); + assertTrue(validator instanceof LocalValidatorFactoryBean); + } + + @Test + public void handlerExceptionResolver() throws Exception { + HandlerExceptionResolverComposite compositeResolver = + (HandlerExceptionResolverComposite) mvcConfiguration.handlerExceptionResolver(); + + assertEquals(0, compositeResolver.getOrder()); + + List expectedResolvers = new ArrayList(); + mvcConfiguration.addDefaultHandlerExceptionResolvers(expectedResolvers); + assertEquals(expectedResolvers.size(), compositeResolver.getExceptionResolvers().size()); + } + + @Test + public void webMvcConfigurerExtensionHooks() throws Exception { + + StaticWebApplicationContext appCxt = new StaticWebApplicationContext(); + appCxt.setServletContext(new MockServletContext(new FileSystemResourceLoader())); + appCxt.registerSingleton("controller", TestController.class); + + WebConfig webConfig = new WebConfig(); + webConfig.setApplicationContext(appCxt); + webConfig.setServletContext(appCxt.getServletContext()); + + String actual = webConfig.mvcConversionService().convert(new TestBean(), String.class); + assertEquals("converted", actual); + + RequestMappingHandlerAdapter adapter = webConfig.requestMappingHandlerAdapter(); + assertEquals(1, adapter.getMessageConverters().size()); + + ConfigurableWebBindingInitializer initializer = (ConfigurableWebBindingInitializer) adapter.getWebBindingInitializer(); + assertNotNull(initializer); + + BeanPropertyBindingResult bindingResult = new BeanPropertyBindingResult(null, ""); + initializer.getValidator().validate(null, bindingResult); + assertEquals("invalid", bindingResult.getAllErrors().get(0).getCode()); + + @SuppressWarnings("unchecked") + List argResolvers= (List) + new DirectFieldAccessor(adapter).getPropertyValue("customArgumentResolvers"); + assertEquals(1, argResolvers.size()); + + @SuppressWarnings("unchecked") + List handlers = (List) + new DirectFieldAccessor(adapter).getPropertyValue("customReturnValueHandlers"); + assertEquals(1, handlers.size()); + + HandlerExceptionResolverComposite composite = (HandlerExceptionResolverComposite) webConfig.handlerExceptionResolver(); + assertEquals(1, composite.getExceptionResolvers().size()); + + RequestMappingHandlerMapping rmHandlerMapping = webConfig.requestMappingHandlerMapping(); + rmHandlerMapping.setApplicationContext(appCxt); + HandlerExecutionChain chain = rmHandlerMapping.getHandler(new MockHttpServletRequest("GET", "/")); + assertNotNull(chain.getInterceptors()); + assertEquals(2, chain.getInterceptors().length); + assertEquals(LocaleChangeInterceptor.class, chain.getInterceptors()[0].getClass()); + assertEquals(ConversionServiceExposingInterceptor.class, chain.getInterceptors()[1].getClass()); + + AbstractHandlerMapping handlerMapping = (AbstractHandlerMapping) webConfig.viewControllerHandlerMapping(); + handlerMapping.setApplicationContext(appCxt); + assertNotNull(handlerMapping); + assertEquals(1, handlerMapping.getOrder()); + HandlerExecutionChain handler = handlerMapping.getHandler(new MockHttpServletRequest("GET", "/path")); + assertNotNull(handler.getHandler()); + + handlerMapping = (AbstractHandlerMapping) webConfig.resourceHandlerMapping(); + handlerMapping.setApplicationContext(appCxt); + assertNotNull(handlerMapping); + assertEquals(Integer.MAX_VALUE-1, handlerMapping.getOrder()); + handler = handlerMapping.getHandler(new MockHttpServletRequest("GET", "/resources/foo.gif")); + assertNotNull(handler.getHandler()); + + handlerMapping = (AbstractHandlerMapping) webConfig.defaultServletHandlerMapping(); + handlerMapping.setApplicationContext(appCxt); + assertNotNull(handlerMapping); + assertEquals(Integer.MAX_VALUE, handlerMapping.getOrder()); + handler = handlerMapping.getHandler(new MockHttpServletRequest("GET", "/anyPath")); + assertNotNull(handler.getHandler()); + } + + @Controller + private static class TestController { + + @SuppressWarnings("unused") + @RequestMapping("/") + public void handle() { + } + } + + private static class TestWebMvcConfiguration extends WebMvcConfigurationSupport { + + } + + /** + * The purpose of this class is to test that an implementation of a {@link WebMvcConfigurer} + * can also apply customizations by extension from {@link WebMvcConfigurationSupport}. + */ + private class WebConfig extends WebMvcConfigurationSupport implements WebMvcConfigurer { + + @Override + public void addFormatters(FormatterRegistry registry) { + registry.addConverter(new Converter() { + public String convert(TestBean source) { + return "converted"; + } + }); + } + + @Override + public void configureMessageConverters(List> converters) { + converters.add(new MappingJacksonHttpMessageConverter()); + } + + @Override + public Validator getValidator() { + return new Validator() { + public void validate(Object target, Errors errors) { + errors.reject("invalid"); + } + public boolean supports(Class clazz) { + return true; + } + }; + } + + @Override + public void addArgumentResolvers(List argumentResolvers) { + argumentResolvers.add(new ModelAttributeMethodProcessor(true)); + } + + @Override + public void addReturnValueHandlers(List returnValueHandlers) { + returnValueHandlers.add(new DefaultMethodReturnValueHandler()); + } + + @Override + public void configureHandlerExceptionResolvers(List exceptionResolvers) { + exceptionResolvers.add(new SimpleMappingExceptionResolver()); + } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(new LocaleChangeInterceptor()); + } + + @Override + public void addViewControllers(ViewControllerRegistry registry) { + registry.addViewController("/path"); + } + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + registry.addResourceHandler("/resources/**").addResourceLocations("src/test/java"); + } + + @Override + public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { + configurer.enable("default"); + } + } + +}