diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/DispatcherServletCustomizer.java b/spring-test/src/main/java/org/springframework/test/web/servlet/DispatcherServletCustomizer.java new file mode 100644 index 00000000000..14ecb8d3ad2 --- /dev/null +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/DispatcherServletCustomizer.java @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2016 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.test.web.servlet; + +import org.springframework.web.servlet.DispatcherServlet; + +/** + * Strategy interface for customizing {@link DispatcherServlet} instances that are + * managed by {@link MockMvc}. + * + * @author Stephane Nicoll + * @since 4.3.4 + */ +public interface DispatcherServletCustomizer { + + /** + * Customize the supplied {@link DispatcherServlet} before it is + * initialized. + * @param dispatcherServlet the dispatcher servlet to customize + */ + void customize(DispatcherServlet dispatcherServlet); + +} diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/MockMvcBuilderSupport.java b/spring-test/src/main/java/org/springframework/test/web/servlet/MockMvcBuilderSupport.java index 046597a518e..3a81051a75e 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/MockMvcBuilderSupport.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/MockMvcBuilderSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.springframework.test.web.servlet; +import java.util.Collections; import java.util.List; import javax.servlet.Filter; import javax.servlet.ServletContext; @@ -24,6 +25,7 @@ import javax.servlet.ServletException; import org.springframework.core.NestedRuntimeException; import org.springframework.mock.web.MockServletConfig; import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.servlet.DispatcherServlet; /** * Base class for MockMvc builder implementations, providing the capability to @@ -35,19 +37,34 @@ import org.springframework.web.context.WebApplicationContext; * * @author Rossen Stoyanchev * @author Rob Winch + * @author Stephane Nicoll * @since 3.2 */ public abstract class MockMvcBuilderSupport { + @Deprecated protected final MockMvc createMockMvc(Filter[] filters, MockServletConfig servletConfig, WebApplicationContext webAppContext, RequestBuilder defaultRequestBuilder, List globalResultMatchers, List globalResultHandlers, Boolean dispatchOptions) { + return createMockMvc(filters, servletConfig, webAppContext, defaultRequestBuilder, + globalResultMatchers, globalResultHandlers, + Collections.singletonList(new DispatchOptionsDispatcherServletCustomizer(dispatchOptions))); + } + + protected final MockMvc createMockMvc(Filter[] filters, MockServletConfig servletConfig, + WebApplicationContext webAppContext, RequestBuilder defaultRequestBuilder, + List globalResultMatchers, List globalResultHandlers, + List dispatcherServletCustomizers) { ServletContext servletContext = webAppContext.getServletContext(); TestDispatcherServlet dispatcherServlet = new TestDispatcherServlet(webAppContext); - dispatcherServlet.setDispatchOptionsRequest(dispatchOptions); + if (dispatcherServletCustomizers != null) { + for (DispatcherServletCustomizer customizers : dispatcherServletCustomizers) { + customizers.customize(dispatcherServlet); + } + } try { dispatcherServlet.init(servletConfig); } @@ -72,4 +89,18 @@ public abstract class MockMvcBuilderSupport { } } + private static class DispatchOptionsDispatcherServletCustomizer + implements DispatcherServletCustomizer { + private final Boolean dispatchOptions; + + private DispatchOptionsDispatcherServletCustomizer(Boolean dispatchOptions) { + this.dispatchOptions = dispatchOptions; + } + + @Override + public void customize(DispatcherServlet dispatcherServlet) { + dispatcherServlet.setDispatchOptionsRequest(this.dispatchOptions); + } + } + } diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/setup/AbstractMockMvcBuilder.java b/spring-test/src/main/java/org/springframework/test/web/servlet/setup/AbstractMockMvcBuilder.java index 50c4db84c27..58c847a57b1 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/setup/AbstractMockMvcBuilder.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/setup/AbstractMockMvcBuilder.java @@ -22,6 +22,7 @@ import javax.servlet.Filter; import javax.servlet.ServletContext; import org.springframework.mock.web.MockServletConfig; +import org.springframework.test.web.servlet.DispatcherServletCustomizer; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvcBuilderSupport; import org.springframework.test.web.servlet.RequestBuilder; @@ -32,6 +33,7 @@ import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.request.RequestPostProcessor; import org.springframework.util.Assert; import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.servlet.DispatcherServlet; /** * An abstract implementation of {@link org.springframework.test.web.servlet.MockMvcBuilder} @@ -42,6 +44,7 @@ import org.springframework.web.context.WebApplicationContext; * pass to the DispatcherServlet. * * @author Rossen Stoyanchev + * @author Stephane Nicoll * @since 4.0 */ public abstract class AbstractMockMvcBuilder> @@ -55,7 +58,7 @@ public abstract class AbstractMockMvcBuilder private final List globalResultHandlers = new ArrayList(); - private Boolean dispatchOptions = Boolean.TRUE; + private final List dispatcherServletCustomizers = new ArrayList(); private final List configurers = new ArrayList(4); @@ -104,11 +107,20 @@ public abstract class AbstractMockMvcBuilder } @SuppressWarnings("unchecked") - public final T dispatchOptions(boolean dispatchOptions) { - this.dispatchOptions = dispatchOptions; + public final T addDispatcherServletCustomizer(DispatcherServletCustomizer customizer) { + this.dispatcherServletCustomizers.add(customizer); return (T) this; } + public final T dispatchOptions(final boolean dispatchOptions) { + return addDispatcherServletCustomizer(new DispatcherServletCustomizer() { + @Override + public void customize(DispatcherServlet dispatcherServlet) { + dispatcherServlet.setDispatchOptionsRequest(dispatchOptions); + } + }); + } + @SuppressWarnings("unchecked") public final T apply(MockMvcConfigurer configurer) { configurer.afterConfigurerAdded(this); @@ -144,7 +156,7 @@ public abstract class AbstractMockMvcBuilder Filter[] filterArray = this.filters.toArray(new Filter[this.filters.size()]); return super.createMockMvc(filterArray, mockServletConfig, wac, this.defaultRequestBuilder, - this.globalResultMatchers, this.globalResultHandlers, this.dispatchOptions); + this.globalResultMatchers, this.globalResultHandlers, this.dispatcherServletCustomizers); } /** diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/setup/DefaultMockMvcBuilderTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/setup/DefaultMockMvcBuilderTests.java index d30ad4180ae..d566fb54a69 100644 --- a/spring-test/src/test/java/org/springframework/test/web/servlet/setup/DefaultMockMvcBuilderTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/servlet/setup/DefaultMockMvcBuilderTests.java @@ -20,11 +20,14 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.springframework.beans.DirectFieldAccessor; import org.springframework.context.support.StaticApplicationContext; import org.springframework.mock.web.MockServletContext; +import org.springframework.test.web.servlet.MockMvc; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.StaticWebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; +import org.springframework.web.servlet.DispatcherServlet; import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; @@ -36,6 +39,7 @@ import static org.springframework.test.web.servlet.setup.MockMvcBuilders.*; * @author Rob Winch * @author Sebastien Deleuze * @author Sam Brannen + * @author Stephane Nicoll */ public class DefaultMockMvcBuilderTests { @@ -124,4 +128,32 @@ public class DefaultMockMvcBuilderTests { assertSame(root, WebApplicationContextUtils.getRequiredWebApplicationContext(this.servletContext)); } + /** + * See /SPR-14277 + */ + @Test + public void dispatcherServletCustomizer() { + StubWebApplicationContext root = new StubWebApplicationContext(this.servletContext); + DefaultMockMvcBuilder builder = webAppContextSetup(root); + builder.addDispatcherServletCustomizer(ds -> ds.setContextId("test-id")); + builder.dispatchOptions(true); + MockMvc mvc = builder.build(); + DispatcherServlet ds = (DispatcherServlet) new DirectFieldAccessor(mvc) + .getPropertyValue("servlet"); + assertEquals("test-id", ds.getContextId()); + } + + @Test + public void dispatcherServletCustomizerProcessedInOrder() { + StubWebApplicationContext root = new StubWebApplicationContext(this.servletContext); + DefaultMockMvcBuilder builder = webAppContextSetup(root); + builder.addDispatcherServletCustomizer(ds -> ds.setContextId("test-id")); + builder.addDispatcherServletCustomizer(ds -> ds.setContextId("override-id")); + builder.dispatchOptions(true); + MockMvc mvc = builder.build(); + DispatcherServlet ds = (DispatcherServlet) new DirectFieldAccessor(mvc) + .getPropertyValue("servlet"); + assertEquals("override-id", ds.getContextId()); + } + }