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.context.web; 018 019import java.util.Set; 020 021import org.springframework.context.ApplicationContextInitializer; 022import org.springframework.context.ConfigurableApplicationContext; 023import org.springframework.core.style.ToStringCreator; 024import org.springframework.test.context.CacheAwareContextLoaderDelegate; 025import org.springframework.test.context.ContextCustomizer; 026import org.springframework.test.context.ContextLoader; 027import org.springframework.test.context.MergedContextConfiguration; 028import org.springframework.util.ObjectUtils; 029import org.springframework.util.StringUtils; 030 031/** 032 * {@code WebMergedContextConfiguration} encapsulates the <em>merged</em> 033 * context configuration declared on a test class and all of its superclasses 034 * via {@link org.springframework.test.context.ContextConfiguration @ContextConfiguration}, 035 * {@link WebAppConfiguration @WebAppConfiguration}, and 036 * {@link org.springframework.test.context.ActiveProfiles @ActiveProfiles}. 037 * 038 * <p>{@code WebMergedContextConfiguration} extends the contract of 039 * {@link MergedContextConfiguration} by adding support for the {@link 040 * #getResourceBasePath() resource base path} configured via {@code @WebAppConfiguration}. 041 * This allows the {@link org.springframework.test.context.TestContext TestContext} 042 * to properly cache the corresponding {@link 043 * org.springframework.web.context.WebApplicationContext WebApplicationContext} 044 * that was loaded using properties of this {@code WebMergedContextConfiguration}. 045 * 046 * @author Sam Brannen 047 * @since 3.2 048 * @see WebAppConfiguration 049 * @see MergedContextConfiguration 050 * @see org.springframework.test.context.ContextConfiguration 051 * @see org.springframework.test.context.ActiveProfiles 052 * @see org.springframework.test.context.ContextConfigurationAttributes 053 * @see org.springframework.test.context.SmartContextLoader#loadContext(MergedContextConfiguration) 054 */ 055public class WebMergedContextConfiguration extends MergedContextConfiguration { 056 057 private static final long serialVersionUID = 7323361588604247458L; 058 059 private final String resourceBasePath; 060 061 062 /** 063 * Create a new {@code WebMergedContextConfiguration} instance for the 064 * supplied parameters. 065 * <p>Delegates to 066 * {@link #WebMergedContextConfiguration(Class, String[], Class[], Set, String[], String[], String[], String, ContextLoader, CacheAwareContextLoaderDelegate, MergedContextConfiguration)}. 067 * @param testClass the test class for which the configuration was merged 068 * @param locations the merged resource locations 069 * @param classes the merged annotated classes 070 * @param contextInitializerClasses the merged context initializer classes 071 * @param activeProfiles the merged active bean definition profiles 072 * @param resourceBasePath the resource path to the root directory of the web application 073 * @param contextLoader the resolved {@code ContextLoader} 074 * @param cacheAwareContextLoaderDelegate a cache-aware context loader 075 * delegate with which to retrieve the parent context 076 * @param parent the parent configuration or {@code null} if there is no parent 077 * @since 3.2.2 078 * @deprecated as of Spring 4.1, use 079 * {@link #WebMergedContextConfiguration(Class, String[], Class[], Set, String[], String[], String[], String, ContextLoader, CacheAwareContextLoaderDelegate, MergedContextConfiguration)} 080 * instead. 081 */ 082 @Deprecated 083 public WebMergedContextConfiguration(Class<?> testClass, String[] locations, Class<?>[] classes, 084 Set<Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>>> contextInitializerClasses, 085 String[] activeProfiles, String resourceBasePath, ContextLoader contextLoader, 086 CacheAwareContextLoaderDelegate cacheAwareContextLoaderDelegate, MergedContextConfiguration parent) { 087 088 this(testClass, locations, classes, contextInitializerClasses, activeProfiles, null, null, resourceBasePath, 089 contextLoader, cacheAwareContextLoaderDelegate, parent); 090 } 091 092 /** 093 * Create a new {@code WebMergedContextConfiguration} instance by copying 094 * all properties from the supplied {@code MergedContextConfiguration}. 095 * <p>If an <em>empty</em> value is supplied for the {@code resourceBasePath} 096 * an empty string will be used. 097 * @param resourceBasePath the resource path to the root directory of the web application 098 * @since 4.1 099 */ 100 public WebMergedContextConfiguration(MergedContextConfiguration mergedConfig, String resourceBasePath) { 101 super(mergedConfig); 102 this.resourceBasePath = !StringUtils.hasText(resourceBasePath) ? "" : resourceBasePath; 103 } 104 105 /** 106 * Create a new {@code WebMergedContextConfiguration} instance for the 107 * supplied parameters. 108 * <p>If a {@code null} value is supplied for {@code locations}, 109 * {@code classes}, {@code activeProfiles}, {@code propertySourceLocations}, 110 * or {@code propertySourceProperties} an empty array will be stored instead. 111 * If a {@code null} value is supplied for the 112 * {@code contextInitializerClasses} an empty set will be stored instead. 113 * If an <em>empty</em> value is supplied for the {@code resourceBasePath} 114 * an empty string will be used. Furthermore, active profiles will be sorted, 115 * and duplicate profiles will be removed. 116 * @param testClass the test class for which the configuration was merged 117 * @param locations the merged resource locations 118 * @param classes the merged annotated classes 119 * @param contextInitializerClasses the merged context initializer classes 120 * @param activeProfiles the merged active bean definition profiles 121 * @param propertySourceLocations the merged {@code PropertySource} locations 122 * @param propertySourceProperties the merged {@code PropertySource} properties 123 * @param resourceBasePath the resource path to the root directory of the web application 124 * @param contextLoader the resolved {@code ContextLoader} 125 * @param cacheAwareContextLoaderDelegate a cache-aware context loader 126 * delegate with which to retrieve the parent context 127 * @param parent the parent configuration or {@code null} if there is no parent 128 * @since 4.1 129 */ 130 public WebMergedContextConfiguration(Class<?> testClass, String[] locations, Class<?>[] classes, 131 Set<Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>>> contextInitializerClasses, 132 String[] activeProfiles, String[] propertySourceLocations, String[] propertySourceProperties, 133 String resourceBasePath, ContextLoader contextLoader, 134 CacheAwareContextLoaderDelegate cacheAwareContextLoaderDelegate, MergedContextConfiguration parent) { 135 136 this(testClass, locations, classes, contextInitializerClasses, activeProfiles, propertySourceLocations, 137 propertySourceProperties, null, resourceBasePath, contextLoader, cacheAwareContextLoaderDelegate, parent); 138 } 139 140 /** 141 * Create a new {@code WebMergedContextConfiguration} instance for the 142 * supplied parameters. 143 * <p>If a {@code null} value is supplied for {@code locations}, 144 * {@code classes}, {@code activeProfiles}, {@code propertySourceLocations}, 145 * or {@code propertySourceProperties} an empty array will be stored instead. 146 * If a {@code null} value is supplied for {@code contextInitializerClasses} 147 * or {@code contextCustomizers}, an empty set will be stored instead. 148 * If an <em>empty</em> value is supplied for the {@code resourceBasePath} 149 * an empty string will be used. Furthermore, active profiles will be sorted, 150 * and duplicate profiles will be removed. 151 * @param testClass the test class for which the configuration was merged 152 * @param locations the merged context resource locations 153 * @param classes the merged annotated classes 154 * @param contextInitializerClasses the merged context initializer classes 155 * @param activeProfiles the merged active bean definition profiles 156 * @param propertySourceLocations the merged {@code PropertySource} locations 157 * @param propertySourceProperties the merged {@code PropertySource} properties 158 * @param contextCustomizers the context customizers 159 * @param resourceBasePath the resource path to the root directory of the web application 160 * @param contextLoader the resolved {@code ContextLoader} 161 * @param cacheAwareContextLoaderDelegate a cache-aware context loader 162 * delegate with which to retrieve the parent context 163 * @param parent the parent configuration or {@code null} if there is no parent 164 * @since 4.3 165 */ 166 public WebMergedContextConfiguration(Class<?> testClass, String[] locations, Class<?>[] classes, 167 Set<Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>>> contextInitializerClasses, 168 String[] activeProfiles, String[] propertySourceLocations, String[] propertySourceProperties, 169 Set<ContextCustomizer> contextCustomizers, String resourceBasePath, ContextLoader contextLoader, 170 CacheAwareContextLoaderDelegate cacheAwareContextLoaderDelegate, MergedContextConfiguration parent) { 171 172 super(testClass, locations, classes, contextInitializerClasses, activeProfiles, propertySourceLocations, 173 propertySourceProperties, contextCustomizers, contextLoader, cacheAwareContextLoaderDelegate, parent); 174 175 this.resourceBasePath = (StringUtils.hasText(resourceBasePath) ? resourceBasePath : ""); 176 } 177 178 /** 179 * Get the resource path to the root directory of the web application for the 180 * {@linkplain #getTestClass() test class}, configured via {@code @WebAppConfiguration}. 181 * @see WebAppConfiguration 182 */ 183 public String getResourceBasePath() { 184 return this.resourceBasePath; 185 } 186 187 188 /** 189 * Determine if the supplied object is equal to this {@code WebMergedContextConfiguration} 190 * instance by comparing both object's {@linkplain #getLocations() locations}, 191 * {@linkplain #getClasses() annotated classes}, 192 * {@linkplain #getContextInitializerClasses() context initializer classes}, 193 * {@linkplain #getActiveProfiles() active profiles}, 194 * {@linkplain #getResourceBasePath() resource base path}, 195 * {@linkplain #getParent() parents}, and the fully qualified names of their 196 * {@link #getContextLoader() ContextLoaders}. 197 */ 198 @Override 199 public boolean equals(Object other) { 200 return (this == other || (super.equals(other) && 201 this.resourceBasePath.equals(((WebMergedContextConfiguration) other).resourceBasePath))); 202 } 203 204 /** 205 * Generate a unique hash code for all properties of this 206 * {@code WebMergedContextConfiguration} excluding the 207 * {@linkplain #getTestClass() test class}. 208 */ 209 @Override 210 public int hashCode() { 211 return super.hashCode() * 31 + this.resourceBasePath.hashCode(); 212 } 213 214 /** 215 * Provide a String representation of the {@linkplain #getTestClass() test class}, 216 * {@linkplain #getLocations() locations}, {@linkplain #getClasses() annotated classes}, 217 * {@linkplain #getContextInitializerClasses() context initializer classes}, 218 * {@linkplain #getActiveProfiles() active profiles}, 219 * {@linkplain #getPropertySourceLocations() property source locations}, 220 * {@linkplain #getPropertySourceProperties() property source properties}, 221 * {@linkplain #getContextCustomizers() context customizers}, 222 * {@linkplain #getResourceBasePath() resource base path}, the name of the 223 * {@link #getContextLoader() ContextLoader}, and the 224 * {@linkplain #getParent() parent configuration}. 225 */ 226 @Override 227 public String toString() { 228 return new ToStringCreator(this) 229 .append("testClass", getTestClass()) 230 .append("locations", ObjectUtils.nullSafeToString(getLocations())) 231 .append("classes", ObjectUtils.nullSafeToString(getClasses())) 232 .append("contextInitializerClasses", ObjectUtils.nullSafeToString(getContextInitializerClasses())) 233 .append("activeProfiles", ObjectUtils.nullSafeToString(getActiveProfiles())) 234 .append("propertySourceLocations", ObjectUtils.nullSafeToString(getPropertySourceLocations())) 235 .append("propertySourceProperties", ObjectUtils.nullSafeToString(getPropertySourceProperties())) 236 .append("contextCustomizers", getContextCustomizers()) 237 .append("resourceBasePath", getResourceBasePath()) 238 .append("contextLoader", nullSafeToString(getContextLoader())) 239 .append("parent", getParent()) 240 .toString(); 241 } 242 243}