001/* 002 * Copyright 2002-2016 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.test.web.servlet.setup; 018 019import java.util.ArrayList; 020import java.util.List; 021import javax.servlet.Filter; 022import javax.servlet.ServletContext; 023 024import org.springframework.mock.web.MockServletConfig; 025import org.springframework.test.web.servlet.DispatcherServletCustomizer; 026import org.springframework.test.web.servlet.MockMvc; 027import org.springframework.test.web.servlet.MockMvcBuilderSupport; 028import org.springframework.test.web.servlet.RequestBuilder; 029import org.springframework.test.web.servlet.ResultHandler; 030import org.springframework.test.web.servlet.ResultMatcher; 031import org.springframework.test.web.servlet.request.ConfigurableSmartRequestBuilder; 032import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; 033import org.springframework.test.web.servlet.request.RequestPostProcessor; 034import org.springframework.util.Assert; 035import org.springframework.web.context.WebApplicationContext; 036import org.springframework.web.servlet.DispatcherServlet; 037 038/** 039 * An abstract implementation of {@link org.springframework.test.web.servlet.MockMvcBuilder} 040 * with common methods for configuring filters, default request properties, global 041 * expectations and global result actions. 042 * <p> 043 * Sub-classes can use different strategies to prepare a WebApplicationContext to 044 * pass to the DispatcherServlet. 045 * 046 * @author Rossen Stoyanchev 047 * @author Stephane Nicoll 048 * @since 4.0 049 */ 050public abstract class AbstractMockMvcBuilder<B extends AbstractMockMvcBuilder<B>> 051 extends MockMvcBuilderSupport implements ConfigurableMockMvcBuilder<B> { 052 053 private List<Filter> filters = new ArrayList<Filter>(); 054 055 private RequestBuilder defaultRequestBuilder; 056 057 private final List<ResultMatcher> globalResultMatchers = new ArrayList<ResultMatcher>(); 058 059 private final List<ResultHandler> globalResultHandlers = new ArrayList<ResultHandler>(); 060 061 private final List<DispatcherServletCustomizer> dispatcherServletCustomizers = new ArrayList<DispatcherServletCustomizer>(); 062 063 private final List<MockMvcConfigurer> configurers = new ArrayList<MockMvcConfigurer>(4); 064 065 066 @SuppressWarnings("unchecked") 067 public final <T extends B> T addFilters(Filter... filters) { 068 Assert.notNull(filters, "filters cannot be null"); 069 070 for (Filter f : filters) { 071 Assert.notNull(f, "filters cannot contain null values"); 072 this.filters.add(f); 073 } 074 return (T) this; 075 } 076 077 @SuppressWarnings("unchecked") 078 public final <T extends B> T addFilter(Filter filter, String... urlPatterns) { 079 080 Assert.notNull(filter, "filter cannot be null"); 081 Assert.notNull(urlPatterns, "urlPatterns cannot be null"); 082 083 if (urlPatterns.length > 0) { 084 filter = new PatternMappingFilterProxy(filter, urlPatterns); 085 } 086 087 this.filters.add(filter); 088 return (T) this; 089 } 090 091 @SuppressWarnings("unchecked") 092 public final <T extends B> T defaultRequest(RequestBuilder requestBuilder) { 093 this.defaultRequestBuilder = requestBuilder; 094 return (T) this; 095 } 096 097 @SuppressWarnings("unchecked") 098 public final <T extends B> T alwaysExpect(ResultMatcher resultMatcher) { 099 this.globalResultMatchers.add(resultMatcher); 100 return (T) this; 101 } 102 103 @SuppressWarnings("unchecked") 104 public final <T extends B> T alwaysDo(ResultHandler resultHandler) { 105 this.globalResultHandlers.add(resultHandler); 106 return (T) this; 107 } 108 109 @SuppressWarnings("unchecked") 110 public final <T extends B> T addDispatcherServletCustomizer(DispatcherServletCustomizer customizer) { 111 this.dispatcherServletCustomizers.add(customizer); 112 return (T) this; 113 } 114 115 public final <T extends B> T dispatchOptions(final boolean dispatchOptions) { 116 return addDispatcherServletCustomizer(new DispatcherServletCustomizer() { 117 @Override 118 public void customize(DispatcherServlet dispatcherServlet) { 119 dispatcherServlet.setDispatchOptionsRequest(dispatchOptions); 120 } 121 }); 122 } 123 124 @SuppressWarnings("unchecked") 125 public final <T extends B> T apply(MockMvcConfigurer configurer) { 126 configurer.afterConfigurerAdded(this); 127 this.configurers.add(configurer); 128 return (T) this; 129 } 130 131 132 /** 133 * Build a {@link org.springframework.test.web.servlet.MockMvc} instance. 134 */ 135 @Override 136 @SuppressWarnings("rawtypes") 137 public final MockMvc build() { 138 139 WebApplicationContext wac = initWebAppContext(); 140 141 ServletContext servletContext = wac.getServletContext(); 142 MockServletConfig mockServletConfig = new MockServletConfig(servletContext); 143 144 for (MockMvcConfigurer configurer : this.configurers) { 145 RequestPostProcessor processor = configurer.beforeMockMvcCreated(this, wac); 146 if (processor != null) { 147 if (this.defaultRequestBuilder == null) { 148 this.defaultRequestBuilder = MockMvcRequestBuilders.get("/"); 149 } 150 if (this.defaultRequestBuilder instanceof ConfigurableSmartRequestBuilder) { 151 ((ConfigurableSmartRequestBuilder) this.defaultRequestBuilder).with(processor); 152 } 153 } 154 } 155 156 Filter[] filterArray = this.filters.toArray(new Filter[this.filters.size()]); 157 158 return super.createMockMvc(filterArray, mockServletConfig, wac, this.defaultRequestBuilder, 159 this.globalResultMatchers, this.globalResultHandlers, this.dispatcherServletCustomizers); 160 } 161 162 /** 163 * A method to obtain the WebApplicationContext to be passed to the DispatcherServlet. 164 * Invoked from {@link #build()} before the 165 * {@link org.springframework.test.web.servlet.MockMvc} instance is created. 166 */ 167 protected abstract WebApplicationContext initWebAppContext(); 168 169}