Skip to content

Commit 78b69f5

Browse files
committed
Always supply test class to ContextLoaders in TCF
Prior to this commit, the following methods in ContextLoaderUtils treated a composed @ContextConfiguration annotation (i.e., a custom annotation that is meta-annotated with @ContextConfiguration) as the "declaring class" instead of the actual test class. - resolveContextConfigurationAttributes() - resolveContextHierarchyAttributes() As a consequence, if @ContextConfiguration is used as a meta-annotation, the meta-annotated class is stored as the "declaringClass" in ContextConfigurationAttributes. Thus, when a ContextLoader (or SmartContextLoader) attempts to detect default resource locations or configuration classes, it does so for the composed annotation class instead of for the declaring test class. This commit ensures that ContextLoaders are supplied the declaring test class instead of the composed annotation class in such use cases. Issue: SPR-11455
1 parent 76cc6db commit 78b69f5

16 files changed

+402
-68
lines changed

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -261,9 +261,9 @@ private static void convertAnnotationAttributesToConfigAttributesAndAddToList(An
261261
* never {@code null}
262262
* @throws IllegalArgumentException if the supplied class is {@code null}; if
263263
* neither {@code @ContextConfiguration} nor {@code @ContextHierarchy} is
264-
* <em>present</em> on the supplied class; or if a given class in the class hierarchy
265-
* declares both {@code @ContextConfiguration} and {@code @ContextHierarchy} as
266-
* top-level annotations.
264+
* <em>present</em> on the supplied class; or if a test class or composed annotation
265+
* in the class hierarchy declares both {@code @ContextConfiguration} and
266+
* {@code @ContextHierarchy} as top-level annotations.
267267
* @throws IllegalStateException if no class in the class hierarchy declares
268268
* {@code @ContextHierarchy}.
269269
*
@@ -296,7 +296,7 @@ static List<List<ContextConfigurationAttributes>> resolveContextHierarchyAttribu
296296
if (contextConfigDeclaredLocally && contextHierarchyDeclaredLocally) {
297297
String msg = String.format("Class [%s] has been configured with both @ContextConfiguration "
298298
+ "and @ContextHierarchy. Only one of these annotations may be declared on a test class "
299-
+ "or custom stereotype annotation.", declaringClass.getName());
299+
+ "or composed annotation.", declaringClass.getName());
300300
logger.error(msg);
301301
throw new IllegalStateException(msg);
302302
}
@@ -305,12 +305,12 @@ static List<List<ContextConfigurationAttributes>> resolveContextHierarchyAttribu
305305

306306
if (contextConfigDeclaredLocally) {
307307
convertAnnotationAttributesToConfigAttributesAndAddToList(descriptor.getAnnotationAttributes(),
308-
declaringClass, configAttributesList);
308+
rootDeclaringClass, configAttributesList);
309309
}
310310
else if (contextHierarchyDeclaredLocally) {
311311
ContextHierarchy contextHierarchy = getAnnotation(declaringClass, contextHierarchyType);
312312
for (ContextConfiguration contextConfiguration : contextHierarchy.value()) {
313-
convertContextConfigToConfigAttributesAndAddToList(contextConfiguration, declaringClass,
313+
convertContextConfigToConfigAttributesAndAddToList(contextConfiguration, rootDeclaringClass,
314314
configAttributesList);
315315
}
316316
}
@@ -428,7 +428,7 @@ static List<ContextConfigurationAttributes> resolveContextConfigurationAttribute
428428

429429
while (descriptor != null) {
430430
convertAnnotationAttributesToConfigAttributesAndAddToList(descriptor.getAnnotationAttributes(),
431-
descriptor.getDeclaringClass(), attributesList);
431+
descriptor.getRootDeclaringClass(), attributesList);
432432
descriptor = findAnnotationDescriptor(descriptor.getRootDeclaringClass().getSuperclass(), annotationType);
433433
}
434434

spring-test/src/test/java/org/springframework/test/context/AbstractContextLoaderUtilsTests.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2014 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -47,11 +47,11 @@ abstract class AbstractContextLoaderUtilsTests {
4747
void assertAttributes(ContextConfigurationAttributes attributes, Class<?> expectedDeclaringClass,
4848
String[] expectedLocations, Class<?>[] expectedClasses,
4949
Class<? extends ContextLoader> expectedContextLoaderClass, boolean expectedInheritLocations) {
50-
assertEquals(expectedDeclaringClass, attributes.getDeclaringClass());
51-
assertArrayEquals(expectedLocations, attributes.getLocations());
52-
assertArrayEquals(expectedClasses, attributes.getClasses());
53-
assertEquals(expectedInheritLocations, attributes.isInheritLocations());
54-
assertEquals(expectedContextLoaderClass, attributes.getContextLoaderClass());
50+
assertEquals("declaring class", expectedDeclaringClass, attributes.getDeclaringClass());
51+
assertArrayEquals("locations", expectedLocations, attributes.getLocations());
52+
assertArrayEquals("classes", expectedClasses, attributes.getClasses());
53+
assertEquals("inherit locations", expectedInheritLocations, attributes.isInheritLocations());
54+
assertEquals("context loader", expectedContextLoaderClass, attributes.getContextLoaderClass());
5555
}
5656

5757
void assertMergedConfig(MergedContextConfiguration mergedConfig, Class<?> expectedTestClass,

spring-test/src/test/java/org/springframework/test/context/ContextLoaderUtilsConfigurationAttributesTests.java

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2014 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -59,11 +59,12 @@ public void resolveConfigAttributesWithConflictingLocations() {
5959

6060
@Test
6161
public void resolveConfigAttributesWithBareAnnotations() {
62-
List<ContextConfigurationAttributes> attributesList = resolveContextConfigurationAttributes(BareAnnotations.class);
62+
Class<BareAnnotations> testClass = BareAnnotations.class;
63+
List<ContextConfigurationAttributes> attributesList = resolveContextConfigurationAttributes(testClass);
6364
assertNotNull(attributesList);
6465
assertEquals(1, attributesList.size());
65-
assertAttributes(attributesList.get(0), BareAnnotations.class, EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY,
66-
ContextLoader.class, true);
66+
assertAttributes(attributesList.get(0), testClass, EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY, ContextLoader.class,
67+
true);
6768
}
6869

6970
@Test
@@ -76,39 +77,43 @@ public void resolveConfigAttributesWithLocalAnnotationAndLocations() {
7677

7778
@Test
7879
public void resolveConfigAttributesWithMetaAnnotationAndLocations() {
79-
List<ContextConfigurationAttributes> attributesList = resolveContextConfigurationAttributes(MetaLocationsFoo.class);
80+
Class<MetaLocationsFoo> testClass = MetaLocationsFoo.class;
81+
List<ContextConfigurationAttributes> attributesList = resolveContextConfigurationAttributes(testClass);
8082
assertNotNull(attributesList);
8183
assertEquals(1, attributesList.size());
82-
assertAttributes(attributesList.get(0), MetaLocationsFooConfig.class, new String[] { "/foo.xml" },
83-
EMPTY_CLASS_ARRAY, ContextLoader.class, true);
84+
assertAttributes(attributesList.get(0), testClass, new String[] { "/foo.xml" }, EMPTY_CLASS_ARRAY,
85+
ContextLoader.class, true);
8486
}
8587

8688
@Test
8789
public void resolveConfigAttributesWithMetaAnnotationAndLocationsAndOverrides() {
88-
List<ContextConfigurationAttributes> attributesList = resolveContextConfigurationAttributes(MetaLocationsFooWithOverrides.class);
90+
Class<MetaLocationsFooWithOverrides> testClass = MetaLocationsFooWithOverrides.class;
91+
List<ContextConfigurationAttributes> attributesList = resolveContextConfigurationAttributes(testClass);
8992
assertNotNull(attributesList);
9093
assertEquals(1, attributesList.size());
91-
assertAttributes(attributesList.get(0), MetaLocationsFooConfigWithOverrides.class, new String[] { "/foo.xml" },
92-
EMPTY_CLASS_ARRAY, ContextLoader.class, true);
94+
assertAttributes(attributesList.get(0), testClass, new String[] { "/foo.xml" }, EMPTY_CLASS_ARRAY,
95+
ContextLoader.class, true);
9396
}
9497

9598
@Test
9699
public void resolveConfigAttributesWithMetaAnnotationAndLocationsAndOverriddenAttributes() {
97-
List<ContextConfigurationAttributes> attributesList = resolveContextConfigurationAttributes(MetaLocationsFooWithOverriddenAttributes.class);
100+
Class<MetaLocationsFooWithOverriddenAttributes> testClass = MetaLocationsFooWithOverriddenAttributes.class;
101+
List<ContextConfigurationAttributes> attributesList = resolveContextConfigurationAttributes(testClass);
98102
assertNotNull(attributesList);
99103
assertEquals(1, attributesList.size());
100-
assertAttributes(attributesList.get(0), MetaLocationsFooConfigWithOverrides.class, new String[] { "foo1.xml",
101-
"foo2.xml" }, EMPTY_CLASS_ARRAY, ContextLoader.class, true);
104+
assertAttributes(attributesList.get(0), testClass, new String[] { "foo1.xml", "foo2.xml" }, EMPTY_CLASS_ARRAY,
105+
ContextLoader.class, true);
102106
}
103107

104108
@Test
105109
public void resolveConfigAttributesWithMetaAnnotationAndLocationsInClassHierarchy() {
106-
List<ContextConfigurationAttributes> attributesList = resolveContextConfigurationAttributes(MetaLocationsBar.class);
110+
Class<MetaLocationsBar> testClass = MetaLocationsBar.class;
111+
List<ContextConfigurationAttributes> attributesList = resolveContextConfigurationAttributes(testClass);
107112
assertNotNull(attributesList);
108113
assertEquals(2, attributesList.size());
109-
assertAttributes(attributesList.get(0), MetaLocationsBarConfig.class, new String[] { "/bar.xml" },
110-
EMPTY_CLASS_ARRAY, ContextLoader.class, true);
111-
assertAttributes(attributesList.get(1), MetaLocationsFooConfig.class, new String[] { "/foo.xml" },
114+
assertAttributes(attributesList.get(0), testClass, new String[] { "/bar.xml" }, EMPTY_CLASS_ARRAY,
115+
ContextLoader.class, true);
116+
assertAttributes(attributesList.get(1), MetaLocationsFoo.class, new String[] { "/foo.xml" },
112117
EMPTY_CLASS_ARRAY, ContextLoader.class, true);
113118
}
114119

spring-test/src/test/java/org/springframework/test/context/ContextLoaderUtilsContextHierarchyTests.java

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2014 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -71,15 +71,16 @@ public void resolveContextHierarchyAttributesForSingleTestClassWithSingleLevelCo
7171

7272
@Test
7373
public void resolveContextHierarchyAttributesForSingleTestClassWithSingleLevelContextHierarchyFromMetaAnnotation() {
74-
List<List<ContextConfigurationAttributes>> hierarchyAttributes = resolveContextHierarchyAttributes(SingleTestClassWithSingleLevelContextHierarchyFromMetaAnnotation.class);
74+
Class<SingleTestClassWithSingleLevelContextHierarchyFromMetaAnnotation> testClass = SingleTestClassWithSingleLevelContextHierarchyFromMetaAnnotation.class;
75+
List<List<ContextConfigurationAttributes>> hierarchyAttributes = resolveContextHierarchyAttributes(testClass);
7576
assertEquals(1, hierarchyAttributes.size());
7677

7778
List<ContextConfigurationAttributes> configAttributesList = hierarchyAttributes.get(0);
7879
assertNotNull(configAttributesList);
7980
assertEquals(1, configAttributesList.size());
8081
debugConfigAttributes(configAttributesList);
81-
assertAttributes(configAttributesList.get(0), ContextHierarchyA.class, new String[] { "A.xml" },
82-
EMPTY_CLASS_ARRAY, ContextLoader.class, true);
82+
assertAttributes(configAttributesList.get(0), testClass, new String[] { "A.xml" }, EMPTY_CLASS_ARRAY,
83+
ContextLoader.class, true);
8384
}
8485

8586
@Test
@@ -131,22 +132,26 @@ public void resolveContextHierarchyAttributesForTestClassHierarchyWithSingleLeve
131132
debugConfigAttributes(configAttributesListClassLevel1);
132133
assertEquals(1, configAttributesListClassLevel1.size());
133134
assertThat(configAttributesListClassLevel1.get(0).getLocations()[0], equalTo("A.xml"));
134-
assertAttributes(configAttributesListClassLevel1.get(0), ContextHierarchyA.class, new String[] { "A.xml" },
135+
assertAttributes(configAttributesListClassLevel1.get(0),
136+
TestClass1WithSingleLevelContextHierarchyFromMetaAnnotation.class, new String[] { "A.xml" },
135137
EMPTY_CLASS_ARRAY, ContextLoader.class, true);
136138

137139
List<ContextConfigurationAttributes> configAttributesListClassLevel2 = hierarchyAttributes.get(1);
138140
debugConfigAttributes(configAttributesListClassLevel2);
139141
assertEquals(1, configAttributesListClassLevel2.size());
140142
assertArrayEquals(new String[] { "B-one.xml", "B-two.xml" },
141143
configAttributesListClassLevel2.get(0).getLocations());
142-
assertAttributes(configAttributesListClassLevel2.get(0), ContextHierarchyB.class, new String[] { "B-one.xml",
144+
assertAttributes(configAttributesListClassLevel2.get(0),
145+
TestClass2WithSingleLevelContextHierarchyFromMetaAnnotation.class,
146+
new String[] { "B-one.xml",
143147
"B-two.xml" }, EMPTY_CLASS_ARRAY, ContextLoader.class, true);
144148

145149
List<ContextConfigurationAttributes> configAttributesListClassLevel3 = hierarchyAttributes.get(2);
146150
debugConfigAttributes(configAttributesListClassLevel3);
147151
assertEquals(1, configAttributesListClassLevel3.size());
148152
assertThat(configAttributesListClassLevel3.get(0).getLocations()[0], equalTo("C.xml"));
149-
assertAttributes(configAttributesListClassLevel3.get(0), ContextHierarchyC.class, new String[] { "C.xml" },
153+
assertAttributes(configAttributesListClassLevel3.get(0),
154+
TestClass3WithSingleLevelContextHierarchyFromMetaAnnotation.class, new String[] { "C.xml" },
150155
EMPTY_CLASS_ARRAY, ContextLoader.class, true);
151156
}
152157

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* Copyright 2002-2014 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.test.context.junit4.annotation.meta;
18+
19+
import java.lang.annotation.ElementType;
20+
import java.lang.annotation.Retention;
21+
import java.lang.annotation.RetentionPolicy;
22+
import java.lang.annotation.Target;
23+
24+
import org.springframework.context.annotation.Bean;
25+
import org.springframework.context.annotation.Configuration;
26+
import org.springframework.context.annotation.Profile;
27+
import org.springframework.test.context.ActiveProfiles;
28+
import org.springframework.test.context.ActiveProfilesResolver;
29+
import org.springframework.test.context.ContextConfiguration;
30+
31+
/**
32+
* Custom configuration annotation with meta-annotation attribute overrides for
33+
* {@link ContextConfiguration#classes} and {@link ActiveProfiles#resolver} and
34+
* with default configuration local to the composed annotation.
35+
*
36+
* @author Sam Brannen
37+
* @since 4.0.3
38+
*/
39+
@ContextConfiguration
40+
@ActiveProfiles
41+
@Retention(RetentionPolicy.RUNTIME)
42+
@Target(ElementType.TYPE)
43+
public @interface ConfigClassesAndProfileResolverWithCustomDefaultsMetaConfig {
44+
45+
@Configuration
46+
@Profile("dev")
47+
static class DevConfig {
48+
49+
@Bean
50+
public String foo() {
51+
return "Dev Foo";
52+
}
53+
}
54+
55+
@Configuration
56+
@Profile("prod")
57+
static class ProductionConfig {
58+
59+
@Bean
60+
public String foo() {
61+
return "Production Foo";
62+
}
63+
}
64+
65+
@Configuration
66+
@Profile("resolver")
67+
static class ResolverConfig {
68+
69+
@Bean
70+
public String foo() {
71+
return "Resolver Foo";
72+
}
73+
}
74+
75+
static class CustomResolver implements ActiveProfilesResolver {
76+
77+
@Override
78+
public String[] resolve(Class<?> testClass) {
79+
return testClass.getSimpleName().equals("ConfigClassesAndProfileResolverWithCustomDefaultsMetaConfigTests") ? new String[] { "resolver" }
80+
: new String[] {};
81+
}
82+
}
83+
84+
85+
Class<?>[] classes() default { DevConfig.class, ProductionConfig.class, ResolverConfig.class };
86+
87+
Class<? extends ActiveProfilesResolver> resolver() default CustomResolver.class;
88+
89+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright 2002-2014 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.test.context.junit4.annotation.meta;
18+
19+
import org.junit.Test;
20+
import org.junit.runner.RunWith;
21+
import org.springframework.beans.factory.annotation.Autowired;
22+
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
23+
24+
import static org.junit.Assert.*;
25+
26+
/**
27+
* Integration tests for meta-annotation attribute override support, relying on
28+
* default attribute values defined in {@link ConfigClassesAndProfileResolverWithCustomDefaultsMetaConfig}.
29+
*
30+
* @author Sam Brannen
31+
* @since 4.0.3
32+
*/
33+
@RunWith(SpringJUnit4ClassRunner.class)
34+
@ConfigClassesAndProfileResolverWithCustomDefaultsMetaConfig
35+
public class ConfigClassesAndProfileResolverWithCustomDefaultsMetaConfigTests {
36+
37+
@Autowired
38+
private String foo;
39+
40+
41+
@Test
42+
public void foo() {
43+
assertEquals("Resolver Foo", foo);
44+
}
45+
}

0 commit comments

Comments
 (0)