Skip to content

Commit 2b5d2e5

Browse files
committed
[SPR-8386] ContextLoader resolution once again ignores the inheritLocations flag on @ContextConfiguration.
1 parent a7ff8a2 commit 2b5d2e5

File tree

1 file changed

+92
-101
lines changed

1 file changed

+92
-101
lines changed

org.springframework.test/src/main/java/org/springframework/test/context/ContextLoaderUtils.java

Lines changed: 92 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -56,146 +56,93 @@ private ContextLoaderUtils() {
5656
/* no-op */
5757
}
5858

59-
/**
60-
* Resolve the list of {@link ContextConfigurationAttributes configuration
61-
* attributes} for the supplied {@link Class class} and its superclasses.
62-
* <p>Note that the {@link ContextConfiguration#inheritLocations
63-
* inheritLocations} flag of {@link ContextConfiguration
64-
* &#064;ContextConfiguration} will be taken into consideration.
65-
* Specifically, if the <code>inheritLocations</code> flag is set to
66-
* <code>true</code>, configuration attributes defined in the annotated
67-
* class will be appended to the configuration attributes defined in
68-
* superclasses.
69-
* @param clazz the class for which to resolve the configuration attributes (must
70-
* not be <code>null</code>)
71-
* @return the list of configuration attributes for the specified class,
72-
* including configuration attributes from superclasses if appropriate
73-
* (never <code>null</code>)
74-
* @throws IllegalArgumentException if the supplied class is <code>null</code>
75-
* or if {@link ContextConfiguration &#064;ContextConfiguration} is not
76-
* <em>present</em> on the supplied class
77-
*/
78-
static List<ContextConfigurationAttributes> resolveContextConfigurationAttributes(Class<?> clazz) {
79-
Assert.notNull(clazz, "Class must not be null");
80-
81-
final List<ContextConfigurationAttributes> attributesList = new ArrayList<ContextConfigurationAttributes>();
82-
83-
Class<ContextConfiguration> annotationType = ContextConfiguration.class;
84-
Class<?> declaringClass = AnnotationUtils.findAnnotationDeclaringClass(annotationType, clazz);
85-
Assert.notNull(declaringClass, String.format(
86-
"Could not find an 'annotation declaring class' for annotation type [%s] and class [%s]", annotationType,
87-
clazz));
88-
89-
while (declaringClass != null) {
90-
ContextConfiguration contextConfiguration = declaringClass.getAnnotation(annotationType);
91-
92-
if (logger.isTraceEnabled()) {
93-
logger.trace(String.format("Retrieved @ContextConfiguration [%s] for declaring class [%s].",
94-
contextConfiguration, declaringClass));
95-
}
96-
97-
ContextConfigurationAttributes attributes = new ContextConfigurationAttributes(declaringClass,
98-
contextConfiguration);
99-
if (logger.isTraceEnabled()) {
100-
logger.trace("Resolved context configuration attributes: " + attributes);
101-
}
102-
103-
attributesList.add(0, attributes);
104-
105-
declaringClass = contextConfiguration.inheritLocations() ? AnnotationUtils.findAnnotationDeclaringClass(
106-
annotationType, declaringClass.getSuperclass()) : null;
107-
}
108-
109-
return attributesList;
110-
}
111-
11259
/**
11360
* Resolve the {@link ContextLoader} {@link Class class} to use for the
114-
* supplied {@link Class testClass} and {@link ContextConfigurationAttributes}
115-
* and then instantiate and return that {@code ContextLoader}.
61+
* supplied {@link Class testClass} and then instantiate and return that
62+
* {@code ContextLoader}.
11663
* <p>If the supplied <code>defaultContextLoaderClassName</code> is
11764
* <code>null</code> or <em>empty</em>, the <em>standard</em>
11865
* default context loader class name {@value #DEFAULT_CONTEXT_LOADER_CLASS_NAME}
11966
* will be used. For details on the class resolution process, see
12067
* {@link #resolveContextLoaderClass()}.
12168
* @param testClass the test class for which the {@code ContextLoader}
12269
* should be resolved (must not be <code>null</code>)
123-
* @param configAttributesList the resolved configuration attributes for the
124-
* test class hierarchy
12570
* @param defaultContextLoaderClassName the name of the default
12671
* {@code ContextLoader} class to use (may be <code>null</code>)
12772
* @return the resolved {@code ContextLoader} for the supplied
12873
* <code>testClass</code> (never <code>null</code>)
12974
* @see #resolveContextLoaderClass()
130-
* @see #resolveContextConfigurationAttributes()
13175
*/
132-
static ContextLoader resolveContextLoader(Class<?> testClass,
133-
List<ContextConfigurationAttributes> configAttributesList, String defaultContextLoaderClassName) {
76+
static ContextLoader resolveContextLoader(Class<?> testClass, String defaultContextLoaderClassName) {
13477
Assert.notNull(testClass, "Test class must not be null");
135-
Assert.notEmpty(configAttributesList, "ContextConfigurationAttributes list must not be null or empty");
13678

13779
if (!StringUtils.hasText(defaultContextLoaderClassName)) {
13880
defaultContextLoaderClassName = DEFAULT_CONTEXT_LOADER_CLASS_NAME;
13981
}
14082

141-
Class<? extends ContextLoader> contextLoaderClass = resolveContextLoaderClass(testClass, configAttributesList,
83+
Class<? extends ContextLoader> contextLoaderClass = resolveContextLoaderClass(testClass,
14284
defaultContextLoaderClassName);
14385

14486
return (ContextLoader) BeanUtils.instantiateClass(contextLoaderClass);
14587
}
14688

14789
/**
14890
* Resolve the {@link ContextLoader} {@link Class} to use for the supplied
149-
* {@link ContextConfigurationAttributes} list.
150-
* <p>This method will iterate over the supplied configuration attributes
151-
* and execute the following algorithm:
91+
* {@link Class testClass}.
15292
* <ol>
153-
* <li>If {@link ContextConfigurationAttributes#getContextLoaderClass()}
154-
* returns an explicit implementation class, that class will be returned.</li>
155-
* <li>If an explicit {@code ContextLoader} implementation class is not
156-
* specified, the next {@link ContextConfigurationAttributes} instance in
157-
* the supplied list will be processed; go to step #1.</li>
158-
* <li>If no explicit <code>loader</code> class is found after processing
159-
* all {@link ContextConfigurationAttributes} instances, an attempt will be
160-
* made to load and return the class with the supplied
161-
* <code>defaultContextLoaderClassName</code>.</li>
93+
* <li>If the {@link ContextConfiguration#loader() loader} attribute of
94+
* {@link ContextConfiguration &#064;ContextConfiguration} is configured
95+
* with an explicit class, that class will be returned.</li>
96+
* <li>If a <code>loader</code> class is not specified, the class hierarchy
97+
* will be traversed to find a parent class annotated with
98+
* {@code @ContextConfiguration}; go to step #1.</li>
99+
* <li>If no explicit <code>loader</code> class is found after traversing
100+
* the class hierarchy, an attempt will be made to load and return the class
101+
* with the supplied <code>defaultContextLoaderClassName</code>.</li>
162102
* </ol>
163103
* @param testClass the class for which to resolve the {@code ContextLoader}
164-
* class; used solely for logging purposes; must not be <code>null</code>
165-
* @param configAttributesList the resolved configuration attributes for the
166-
* test class hierarchy; must not be <code>null</code> or empty
104+
* class; must not be <code>null</code>
167105
* @param defaultContextLoaderClassName the name of the default
168106
* {@code ContextLoader} class to use; must not be <code>null</code> or empty
169-
* @return the {@code ContextLoader} class to use for the specified class
170-
* (never <code>null</code>)
107+
* @return the {@code ContextLoader} class to use for the supplied test class
171108
* @throws IllegalArgumentException if {@code @ContextConfiguration} is not
172-
* <em>present</em> on the supplied test class
173-
* @see #resolveContextLoader()
174-
* @see #resolveContextConfigurationAttributes()
109+
* <em>present</em> on the supplied test class
110+
* @throws IllegalStateException if the default {@code ContextLoader} class
111+
* could not be loaded
175112
*/
176113
@SuppressWarnings("unchecked")
177114
static Class<? extends ContextLoader> resolveContextLoaderClass(Class<?> testClass,
178-
List<ContextConfigurationAttributes> configAttributesList, String defaultContextLoaderClassName) {
115+
String defaultContextLoaderClassName) {
179116
Assert.notNull(testClass, "Class must not be null");
180-
Assert.notEmpty(configAttributesList, "ContextConfigurationAttributes list must not be null or empty");
181117
Assert.hasText(defaultContextLoaderClassName, "Default ContextLoader class name must not be null or empty");
182118

183-
for (ContextConfigurationAttributes configAttributes : configAttributesList) {
119+
Class<ContextConfiguration> annotationType = ContextConfiguration.class;
120+
Class<?> declaringClass = AnnotationUtils.findAnnotationDeclaringClass(annotationType, testClass);
121+
Assert.notNull(declaringClass, String.format(
122+
"Could not find an 'annotation declaring class' for annotation type [%s] and test class [%s]",
123+
annotationType, testClass));
124+
125+
while (declaringClass != null) {
126+
ContextConfiguration contextConfiguration = declaringClass.getAnnotation(annotationType);
127+
184128
if (logger.isTraceEnabled()) {
185129
logger.trace(String.format(
186-
"Processing ContextLoader for context configuration attributes [%s] and test class [%s]",
187-
configAttributes, testClass));
130+
"Processing ContextLoader for @ContextConfiguration [%s] and declaring class [%s]",
131+
contextConfiguration, declaringClass));
188132
}
189133

190-
Class<? extends ContextLoader> contextLoaderClass = configAttributes.getContextLoaderClass();
134+
Class<? extends ContextLoader> contextLoaderClass = contextConfiguration.loader();
191135
if (!ContextLoader.class.equals(contextLoaderClass)) {
192136
if (logger.isDebugEnabled()) {
193137
logger.debug(String.format(
194-
"Found explicit ContextLoader class [%s] for context configuration attributes [%s] and test class [%s]",
195-
contextLoaderClass, configAttributes, testClass));
138+
"Found explicit ContextLoader class [%s] for @ContextConfiguration [%s] and declaring class [%s]",
139+
contextLoaderClass, contextConfiguration, declaringClass));
196140
}
197141
return contextLoaderClass;
198142
}
143+
144+
declaringClass = AnnotationUtils.findAnnotationDeclaringClass(annotationType,
145+
declaringClass.getSuperclass());
199146
}
200147

201148
try {
@@ -213,6 +160,58 @@ static Class<? extends ContextLoader> resolveContextLoaderClass(Class<?> testCla
213160
}
214161
}
215162

163+
/**
164+
* Resolve the list of {@link ContextConfigurationAttributes configuration
165+
* attributes} for the supplied {@link Class class} and its superclasses.
166+
* <p>Note that the {@link ContextConfiguration#inheritLocations
167+
* inheritLocations} flag of {@link ContextConfiguration
168+
* &#064;ContextConfiguration} will be taken into consideration.
169+
* Specifically, if the <code>inheritLocations</code> flag is set to
170+
* <code>true</code>, configuration attributes defined in the annotated
171+
* class will be appended to the configuration attributes defined in
172+
* superclasses.
173+
* @param clazz the class for which to resolve the configuration attributes (must
174+
* not be <code>null</code>)
175+
* @return the list of configuration attributes for the specified class,
176+
* including configuration attributes from superclasses if appropriate
177+
* (never <code>null</code>)
178+
* @throws IllegalArgumentException if the supplied class is <code>null</code> or
179+
* if {@code @ContextConfiguration} is not <em>present</em> on the supplied class
180+
*/
181+
static List<ContextConfigurationAttributes> resolveContextConfigurationAttributes(Class<?> clazz) {
182+
Assert.notNull(clazz, "Class must not be null");
183+
184+
final List<ContextConfigurationAttributes> attributesList = new ArrayList<ContextConfigurationAttributes>();
185+
186+
Class<ContextConfiguration> annotationType = ContextConfiguration.class;
187+
Class<?> declaringClass = AnnotationUtils.findAnnotationDeclaringClass(annotationType, clazz);
188+
Assert.notNull(declaringClass, String.format(
189+
"Could not find an 'annotation declaring class' for annotation type [%s] and class [%s]", annotationType,
190+
clazz));
191+
192+
while (declaringClass != null) {
193+
ContextConfiguration contextConfiguration = declaringClass.getAnnotation(annotationType);
194+
195+
if (logger.isTraceEnabled()) {
196+
logger.trace(String.format("Retrieved @ContextConfiguration [%s] for declaring class [%s].",
197+
contextConfiguration, declaringClass));
198+
}
199+
200+
ContextConfigurationAttributes attributes = new ContextConfigurationAttributes(declaringClass,
201+
contextConfiguration);
202+
if (logger.isTraceEnabled()) {
203+
logger.trace("Resolved context configuration attributes: " + attributes);
204+
}
205+
206+
attributesList.add(0, attributes);
207+
208+
declaringClass = contextConfiguration.inheritLocations() ? AnnotationUtils.findAnnotationDeclaringClass(
209+
annotationType, declaringClass.getSuperclass()) : null;
210+
}
211+
212+
return attributesList;
213+
}
214+
216215
/**
217216
* Resolve <em>active bean definition profiles</em> for the supplied {@link Class}.
218217
* <p>Note that the {@link ActiveProfiles#inheritProfiles inheritProfiles}
@@ -286,8 +285,8 @@ else if (!ObjectUtils.isEmpty(valueProfiles)) {
286285
* @param defaultContextLoaderClassName the name of the default
287286
* {@code ContextLoader} class to use (may be <code>null</code>)
288287
* @return the merged context configuration
289-
* @see #resolveContextConfigurationAttributes()
290288
* @see #resolveContextLoader()
289+
* @see #resolveContextConfigurationAttributes()
291290
* @see SmartContextLoader#processContextConfiguration()
292291
* @see ContextLoader#processLocations()
293292
* @see #resolveActiveProfiles()
@@ -296,16 +295,8 @@ else if (!ObjectUtils.isEmpty(valueProfiles)) {
296295
static MergedContextConfiguration buildMergedContextConfiguration(Class<?> testClass,
297296
String defaultContextLoaderClassName) {
298297

299-
List<ContextConfigurationAttributes> configAttributesList = resolveContextConfigurationAttributes(testClass);
300-
301-
ContextLoader contextLoader = resolveContextLoader(testClass, configAttributesList,
302-
defaultContextLoaderClassName);
303-
304-
// Algorithm:
305-
// - iterate over config attributes
306-
// -- let loader process locations
307-
// -- let loader process classes, if it's a SmartContextLoader
308-
298+
final ContextLoader contextLoader = resolveContextLoader(testClass, defaultContextLoaderClassName);
299+
final List<ContextConfigurationAttributes> configAttributesList = resolveContextConfigurationAttributes(testClass);
309300
final List<String> locationsList = new ArrayList<String>();
310301
final List<Class<?>> classesList = new ArrayList<Class<?>>();
311302

0 commit comments

Comments
 (0)