Skip to content

Commit 58daeea

Browse files
committed
Merge pull request #121 from sbrannen/SPR-9011
* SPR-9011: Support ApplicationContextInitializers in the TCF
2 parents 9c8c967 + 1f93777 commit 58daeea

24 files changed

+1596
-261
lines changed

spring-test/.springBeans

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<beansProjectDescription>
33
<version>1</version>
4-
<pluginVersion><![CDATA[2.6.0.201104111100-PATCH]]></pluginVersion>
4+
<pluginVersion><![CDATA[3.0.0.201208090952-RELEASE]]></pluginVersion>
55
<configSuffixes>
66
<configSuffix><![CDATA[xml]]></configSuffix>
77
</configSuffixes>
88
<enableImports><![CDATA[false]]></enableImports>
99
<configs>
1010
<config>src/test/java/org/springframework/test/context/junit4/profile/xml/DefaultProfileXmlConfigTests-context.xml</config>
11+
<config>src/test/java/org/springframework/test/context/junit4/aci/xml/MultipleInitializersXmlConfigTests-context.xml</config>
1112
</configs>
1213
<configSets>
1314
</configSets>

spring-test/src/main/java/org/springframework/test/context/ContextConfiguration.java

Lines changed: 76 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,19 @@
2323
import java.lang.annotation.RetentionPolicy;
2424
import java.lang.annotation.Target;
2525

26-
import org.springframework.context.annotation.Bean;
27-
import org.springframework.context.annotation.Configuration;
26+
import org.springframework.context.ApplicationContextInitializer;
27+
import org.springframework.context.ConfigurableApplicationContext;
2828

2929
/**
30-
* {@code ContextConfiguration} defines class-level metadata that is
30+
* {@code @ContextConfiguration} defines class-level metadata that is
3131
* used to determine how to load and configure an
3232
* {@link org.springframework.context.ApplicationContext ApplicationContext}
33-
* for test classes.
33+
* for integration tests.
3434
*
3535
* <h3>Supported Resource Types</h3>
3636
*
3737
* <p>Prior to Spring 3.1, only path-based resource locations were supported.
38-
* As of Spring 3.1, {@link #loader context loaders} may choose to support
38+
* As of Spring 3.1, {@linkplain #loader context loaders} may choose to support
3939
* either path-based or class-based resources (but not both). Consequently
4040
* {@code @ContextConfiguration} can be used to declare either path-based
4141
* resource locations (via the {@link #locations} or {@link #value}
@@ -47,16 +47,20 @@
4747
* <p>The term <em>annotated class</em> can refer to any of the following.
4848
*
4949
* <ul>
50-
* <li>A class annotated with {@link Configuration @Configuration}</li>
50+
* <li>A class annotated with
51+
* {@link org.springframework.context.annotation.Configuration @Configuration}</li>
5152
* <li>A component (i.e., a class annotated with
5253
* {@link org.springframework.stereotype.Component @Component},
5354
* {@link org.springframework.stereotype.Service @Service},
5455
* {@link org.springframework.stereotype.Repository @Repository}, etc.)</li>
5556
* <li>A JSR-330 compliant class that is annotated with {@code javax.inject} annotations</li>
56-
* <li>Any other class that contains {@link Bean @Bean}-methods</li>
57+
* <li>Any other class that contains
58+
* {@link org.springframework.context.annotation.Bean @Bean}-methods</li>
5759
* </ul>
5860
*
59-
* Consult the JavaDoc for {@link Configuration @Configuration} and {@link Bean @Bean}
61+
* Consult the Javadoc for
62+
* {@link org.springframework.context.annotation.Configuration @Configuration} and
63+
* {@link org.springframework.context.annotation.Bean @Bean}
6064
* for further information regarding the configuration and semantics of
6165
* <em>annotated classes</em>.
6266
*
@@ -66,8 +70,8 @@
6670
* @see SmartContextLoader
6771
* @see ContextConfigurationAttributes
6872
* @see MergedContextConfiguration
69-
* @see org.springframework.context.ApplicationContext
7073
* @see ActiveProfiles
74+
* @see org.springframework.context.ApplicationContext
7175
*/
7276
@Documented
7377
@Inherited
@@ -82,6 +86,7 @@
8286
* with {@link #locations} or {@link #classes}, but it may be used
8387
* instead of {@link #locations}.
8488
* @since 3.0
89+
* @see #inheritLocations
8590
*/
8691
String[] value() default {};
8792

@@ -111,6 +116,7 @@
111116
* {@link #value} or {@link #classes}, but it may be used instead of
112117
* {@link #value}.
113118
* @since 2.5
119+
* @see #inheritLocations
114120
*/
115121
String[] locations() default {};
116122

@@ -131,9 +137,31 @@
131137
* @since 3.1
132138
* @see org.springframework.context.annotation.Configuration
133139
* @see org.springframework.test.context.support.AnnotationConfigContextLoader
140+
* @see #inheritLocations
134141
*/
135142
Class<?>[] classes() default {};
136143

144+
/**
145+
* The application context <em>initializer classes</em> to use for initializing
146+
* a {@link ConfigurableApplicationContext}.
147+
*
148+
* <p>The concrete {@code ConfigurableApplicationContext} type supported by each
149+
* declared initializer must be compatible with the type of {@code ApplicationContext}
150+
* created by the {@link SmartContextLoader} in use.
151+
*
152+
* <p>{@code SmartContextLoader} implementations typically detect whether
153+
* Spring's {@link org.springframework.core.Ordered Ordered} interface has been
154+
* implemented or if the @{@link org.springframework.core.annotation.Order Order}
155+
* annotation is present and sort instances accordingly prior to invoking them.
156+
*
157+
* @since 3.2
158+
* @see org.springframework.context.ApplicationContextInitializer
159+
* @see org.springframework.context.ConfigurableApplicationContext
160+
* @see #inheritInitializers
161+
* @see #loader
162+
*/
163+
Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>>[] initializers() default {};
164+
137165
/**
138166
* Whether or not {@link #locations resource locations} or <em>annotated
139167
* classes</em> from test superclasses should be <em>inherited</em>.
@@ -194,7 +222,45 @@
194222
boolean inheritLocations() default true;
195223

196224
/**
197-
* The type of {@link ContextLoader} (or {@link SmartContextLoader}) to use
225+
* Whether or not {@linkplain #initializers context initializers} from test
226+
* superclasses should be <em>inherited</em>.
227+
*
228+
* <p>The default value is <code>true</code>. This means that an annotated
229+
* class will <em>inherit</em> the application context initializers defined
230+
* by test superclasses. Specifically, the initializers for a given test
231+
* class will be added to the set of initializers defined by test
232+
* superclasses. Thus, subclasses have the option of <em>extending</em> the
233+
* set of initializers.
234+
*
235+
* <p>If <code>inheritInitializers</code> is set to <code>false</code>, the
236+
* initializers for the annotated class will <em>shadow</em> and effectively
237+
* replace any initializers defined by superclasses.
238+
*
239+
* <p>In the following example, the
240+
* {@link org.springframework.context.ApplicationContext ApplicationContext}
241+
* for {@code ExtendedTest} will be initialized using
242+
* {@code BaseInitializer} <strong>and</strong> {@code ExtendedInitializer}.
243+
* Note, however, that the order in which the initializers are invoked
244+
* depends on whether they implement {@link org.springframework.core.Ordered
245+
* Ordered} or are annotated with {@link org.springframework.core.annotation.Order
246+
* &#064;Order}.
247+
* <pre class="code">
248+
* &#064;ContextConfiguration(initializers = BaseInitializer.class)
249+
* public class BaseTest {
250+
* // ...
251+
* }
252+
*
253+
* &#064;ContextConfiguration(initializers = ExtendedInitializer.class)
254+
* public class ExtendedTest extends BaseTest {
255+
* // ...
256+
* }
257+
* </pre>
258+
* @since 3.2
259+
*/
260+
boolean inheritInitializers() default true;
261+
262+
/**
263+
* The type of {@link SmartContextLoader} (or {@link ContextLoader}) to use
198264
* for loading an {@link org.springframework.context.ApplicationContext
199265
* ApplicationContext}.
200266
*

spring-test/src/main/java/org/springframework/test/context/ContextConfigurationAttributes.java

Lines changed: 79 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,15 @@
1818

1919
import org.apache.commons.logging.Log;
2020
import org.apache.commons.logging.LogFactory;
21+
22+
import org.springframework.context.ApplicationContextInitializer;
23+
import org.springframework.context.ConfigurableApplicationContext;
2124
import org.springframework.core.style.ToStringCreator;
2225
import org.springframework.util.Assert;
2326
import org.springframework.util.ObjectUtils;
2427

2528
/**
26-
* <code>ContextConfigurationAttributes</code> encapsulates the context
29+
* {@code ContextConfigurationAttributes} encapsulates the context
2730
* configuration attributes declared on a test class via
2831
* {@link ContextConfiguration @ContextConfiguration}.
2932
*
@@ -47,6 +50,10 @@ public class ContextConfigurationAttributes {
4750

4851
private final Class<? extends ContextLoader> contextLoaderClass;
4952

53+
private final Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>>[] initializers;
54+
55+
private final boolean inheritInitializers;
56+
5057

5158
/**
5259
* Resolve resource locations from the {@link ContextConfiguration#locations() locations}
@@ -68,8 +75,7 @@ private static String[] resolveLocations(Class<?> declaringClass, ContextConfigu
6875
ObjectUtils.nullSafeToString(valueLocations), ObjectUtils.nullSafeToString(locations));
6976
logger.error(msg);
7077
throw new IllegalStateException(msg);
71-
}
72-
else if (!ObjectUtils.isEmpty(valueLocations)) {
78+
} else if (!ObjectUtils.isEmpty(valueLocations)) {
7379
locations = valueLocations;
7480
}
7581

@@ -79,31 +85,59 @@ else if (!ObjectUtils.isEmpty(valueLocations)) {
7985
/**
8086
* Construct a new {@link ContextConfigurationAttributes} instance for the
8187
* supplied {@link ContextConfiguration @ContextConfiguration} annotation and
82-
* the {@link Class test class} that declared it.
88+
* the {@linkplain Class test class} that declared it.
8389
* @param declaringClass the test class that declared {@code @ContextConfiguration}
8490
* @param contextConfiguration the annotation from which to retrieve the attributes
8591
*/
8692
public ContextConfigurationAttributes(Class<?> declaringClass, ContextConfiguration contextConfiguration) {
8793
this(declaringClass, resolveLocations(declaringClass, contextConfiguration), contextConfiguration.classes(),
88-
contextConfiguration.inheritLocations(), contextConfiguration.loader());
94+
contextConfiguration.inheritLocations(), contextConfiguration.initializers(),
95+
contextConfiguration.inheritInitializers(), contextConfiguration.loader());
8996
}
9097

9198
/**
9299
* Construct a new {@link ContextConfigurationAttributes} instance for the
93-
* {@link Class test class} that declared the
100+
* {@linkplain Class test class} that declared the
94101
* {@link ContextConfiguration @ContextConfiguration} annotation and its
95102
* corresponding attributes.
96103
*
97104
* @param declaringClass the test class that declared {@code @ContextConfiguration}
98105
* @param locations the resource locations declared via {@code @ContextConfiguration}
99106
* @param classes the annotated classes declared via {@code @ContextConfiguration}
100-
* @param inheritLocations the <code>inheritLocations</code> flag declared via {@code @ContextConfiguration}
107+
* @param inheritLocations the {@code inheritLocations} flag declared via {@code @ContextConfiguration}
101108
* @param contextLoaderClass the {@code ContextLoader} class declared via {@code @ContextConfiguration}
102109
* @throws IllegalArgumentException if the {@code declaringClass} or {@code contextLoaderClass} is
103-
* <code>null</code>, or if the {@code locations} and {@code classes} are both non-empty
110+
* {@code null}, or if the {@code locations} and {@code classes} are both non-empty
111+
* @deprecated as of Spring 3.2, use
112+
* {@link #ContextConfigurationAttributes(Class, String[], Class[], boolean, Class[], boolean, Class)}
113+
* instead
104114
*/
115+
@Deprecated
105116
public ContextConfigurationAttributes(Class<?> declaringClass, String[] locations, Class<?>[] classes,
106117
boolean inheritLocations, Class<? extends ContextLoader> contextLoaderClass) {
118+
this(declaringClass, locations, classes, inheritLocations, null, true, contextLoaderClass);
119+
}
120+
121+
/**
122+
* Construct a new {@link ContextConfigurationAttributes} instance for the
123+
* {@linkplain Class test class} that declared the
124+
* {@link ContextConfiguration @ContextConfiguration} annotation and its
125+
* corresponding attributes.
126+
*
127+
* @param declaringClass the test class that declared {@code @ContextConfiguration}
128+
* @param locations the resource locations declared via {@code @ContextConfiguration}
129+
* @param classes the annotated classes declared via {@code @ContextConfiguration}
130+
* @param inheritLocations the {@code inheritLocations} flag declared via {@code @ContextConfiguration}
131+
* @param initializers the context initializers declared via {@code @ContextConfiguration}
132+
* @param inheritInitializers the {@code inheritInitializers} flag declared via {@code @ContextConfiguration}
133+
* @param contextLoaderClass the {@code ContextLoader} class declared via {@code @ContextConfiguration}
134+
* @throws IllegalArgumentException if the {@code declaringClass} or {@code contextLoaderClass} is
135+
* {@code null}, or if the {@code locations} and {@code classes} are both non-empty
136+
*/
137+
public ContextConfigurationAttributes(Class<?> declaringClass, String[] locations, Class<?>[] classes,
138+
boolean inheritLocations,
139+
Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>>[] initializers,
140+
boolean inheritInitializers, Class<? extends ContextLoader> contextLoaderClass) {
107141

108142
Assert.notNull(declaringClass, "declaringClass must not be null");
109143
Assert.notNull(contextLoaderClass, "contextLoaderClass must not be null");
@@ -122,14 +156,16 @@ public ContextConfigurationAttributes(Class<?> declaringClass, String[] location
122156
this.locations = locations;
123157
this.classes = classes;
124158
this.inheritLocations = inheritLocations;
159+
this.initializers = initializers;
160+
this.inheritInitializers = inheritInitializers;
125161
this.contextLoaderClass = contextLoaderClass;
126162
}
127163

128164
/**
129-
* Get the {@link Class class} that declared the
165+
* Get the {@linkplain Class class} that declared the
130166
* {@link ContextConfiguration @ContextConfiguration} annotation.
131167
*
132-
* @return the declaring class; never <code>null</code>
168+
* @return the declaring class; never {@code null}
133169
*/
134170
public Class<?> getDeclaringClass() {
135171
return declaringClass;
@@ -143,7 +179,7 @@ public Class<?> getDeclaringClass() {
143179
* represent a <em>processed</em> value that does not match the original value
144180
* declared via {@link ContextConfiguration @ContextConfiguration}.
145181
*
146-
* @return the resource locations; potentially <code>null</code> or <em>empty</em>
182+
* @return the resource locations; potentially {@code null} or <em>empty</em>
147183
* @see ContextConfiguration#value
148184
* @see ContextConfiguration#locations
149185
* @see #setLocations(String[])
@@ -170,7 +206,7 @@ public void setLocations(String[] locations) {
170206
* represent a <em>processed</em> value that does not match the original value
171207
* declared via {@link ContextConfiguration @ContextConfiguration}.
172208
*
173-
* @return the annotated classes; potentially <code>null</code> or <em>empty</em>
209+
* @return the annotated classes; potentially {@code null} or <em>empty</em>
174210
* @see ContextConfiguration#classes
175211
* @see #setClasses(Class[])
176212
*/
@@ -192,7 +228,7 @@ public void setClasses(Class<?>[] classes) {
192228
* Determine if this {@code ContextConfigurationAttributes} instance has
193229
* path-based resource locations.
194230
*
195-
* @return <code>true</code> if the {@link #getLocations() locations} array is not empty
231+
* @return {@code true} if the {@link #getLocations() locations} array is not empty
196232
* @see #hasResources()
197233
* @see #hasClasses()
198234
*/
@@ -204,7 +240,7 @@ public boolean hasLocations() {
204240
* Determine if this {@code ContextConfigurationAttributes} instance has
205241
* class-based resources.
206242
*
207-
* @return <code>true</code> if the {@link #getClasses() classes} array is not empty
243+
* @return {@code true} if the {@link #getClasses() classes} array is not empty
208244
* @see #hasResources()
209245
* @see #hasLocations()
210246
*/
@@ -216,7 +252,7 @@ public boolean hasClasses() {
216252
* Determine if this {@code ContextConfigurationAttributes} instance has
217253
* either path-based resource locations or class-based resources.
218254
*
219-
* @return <code>true</code> if either the {@link #getLocations() locations}
255+
* @return {@code true} if either the {@link #getLocations() locations}
220256
* or the {@link #getClasses() classes} array is not empty
221257
* @see #hasLocations()
222258
* @see #hasClasses()
@@ -226,21 +262,43 @@ public boolean hasResources() {
226262
}
227263

228264
/**
229-
* Get the <code>inheritLocations</code> flag that was declared via
265+
* Get the {@code inheritLocations} flag that was declared via
230266
* {@link ContextConfiguration @ContextConfiguration}.
231267
*
232-
* @return the <code>inheritLocations</code> flag
268+
* @return the {@code inheritLocations} flag
233269
* @see ContextConfiguration#inheritLocations
234270
*/
235271
public boolean isInheritLocations() {
236272
return inheritLocations;
237273
}
238274

239275
/**
240-
* Get the <code>ContextLoader</code> class that was declared via
276+
* Get the {@code ApplicationContextInitializer} classes that were declared via
277+
* {@link ContextConfiguration @ContextConfiguration}.
278+
*
279+
* @return the {@code ApplicationContextInitializer} classes
280+
* @since 3.2
281+
*/
282+
public Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>>[] getInitializers() {
283+
return initializers;
284+
}
285+
286+
/**
287+
* Get the {@code inheritInitializers} flag that was declared via
288+
* {@link ContextConfiguration @ContextConfiguration}.
289+
*
290+
* @return the {@code inheritInitializers} flag
291+
* @since 3.2
292+
*/
293+
public boolean isInheritInitializers() {
294+
return inheritInitializers;
295+
}
296+
297+
/**
298+
* Get the {@code ContextLoader} class that was declared via
241299
* {@link ContextConfiguration @ContextConfiguration}.
242300
*
243-
* @return the <code>ContextLoader</code> class
301+
* @return the {@code ContextLoader} class
244302
* @see ContextConfiguration#loader
245303
*/
246304
public Class<? extends ContextLoader> getContextLoaderClass() {
@@ -258,6 +316,8 @@ public String toString() {
258316
.append("locations", ObjectUtils.nullSafeToString(locations))//
259317
.append("classes", ObjectUtils.nullSafeToString(classes))//
260318
.append("inheritLocations", inheritLocations)//
319+
.append("initializers", ObjectUtils.nullSafeToString(initializers))//
320+
.append("inheritInitializers", inheritInitializers)//
261321
.append("contextLoaderClass", contextLoaderClass.getName())//
262322
.toString();
263323
}

0 commit comments

Comments
 (0)