Skip to content

Commit 2d91838

Browse files
committed
Support @configuration as meta-annotation in the TCF
Spring Framework 4.0 introduced support for using test-related annotations as meta-annotations in the Spring TestContext Framework (TCF) in order to create custom composed annotations within a test suite; however, the detection of default @configuration classes in test classes was not updated to search for @configuration declared as a meta-annotation. Specifically, AnnotationConfigContextLoaderUtils invokes Class.isAnnotated() which only searches for annotations declared directly on the class in question. This commit addresses this issue by refactoring the isDefaultConfigurationClassCandidate() method in AnnotationConfigContextLoaderUtils so that it uses AnnotationUtils.findAnnotation() instead of Class.isAnnotated() for detecting the presence of the @configuration annotation, either directly or as a meta-annotation. Issue: SPR-12659
1 parent c5c32ec commit 2d91838

File tree

2 files changed

+93
-2
lines changed

2 files changed

+93
-2
lines changed

spring-test/src/main/java/org/springframework/test/context/support/AnnotationConfigContextLoaderUtils.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.apache.commons.logging.LogFactory;
2525

2626
import org.springframework.context.annotation.Configuration;
27+
import org.springframework.core.annotation.AnnotationUtils;
2728
import org.springframework.test.context.SmartContextLoader;
2829
import org.springframework.util.Assert;
2930

@@ -95,13 +96,14 @@ public static Class<?>[] detectDefaultConfigurationClasses(Class<?> declaringCla
9596
* <li>must not be {@code private}</li>
9697
* <li>must not be {@code final}</li>
9798
* <li>must be {@code static}</li>
98-
* <li>must be annotated with {@code @Configuration}</li>
99+
* <li>must be annotated or meta-annotated with {@code @Configuration}</li>
99100
* </ul>
100101
* @param clazz the class to check
101102
* @return {@code true} if the supplied class meets the candidate criteria
102103
*/
103104
private static boolean isDefaultConfigurationClassCandidate(Class<?> clazz) {
104-
return (clazz != null && isStaticNonPrivateAndNonFinal(clazz) && clazz.isAnnotationPresent(Configuration.class));
105+
return (clazz != null && isStaticNonPrivateAndNonFinal(clazz) &&
106+
(AnnotationUtils.findAnnotation(clazz, Configuration.class) != null));
105107
}
106108

107109
private static boolean isStaticNonPrivateAndNonFinal(Class<?> clazz) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* Copyright 2002-2015 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.support;
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.junit.Test;
25+
import org.springframework.context.annotation.Configuration;
26+
27+
import static org.junit.Assert.*;
28+
import static org.springframework.test.context.support.AnnotationConfigContextLoaderUtils.*;
29+
30+
/**
31+
* Unit tests for {@link AnnotationConfigContextLoaderUtils}.
32+
*
33+
* @author Sam Brannen
34+
* @since 4.1.5
35+
*/
36+
public class AnnotationConfigContextLoaderUtilsTests {
37+
38+
@Test(expected = IllegalArgumentException.class)
39+
public void detectDefaultConfigurationClassesWithNullDeclaringClass() {
40+
detectDefaultConfigurationClasses(null);
41+
}
42+
43+
@Test
44+
public void detectDefaultConfigurationClassesWithoutConfigurationClass() {
45+
Class<?>[] configClasses = detectDefaultConfigurationClasses(NoConfigTestCase.class);
46+
assertNotNull(configClasses);
47+
assertEquals(0, configClasses.length);
48+
}
49+
50+
@Test
51+
public void detectDefaultConfigurationClassesWithExplicitConfigurationAnnotation() {
52+
Class<?>[] configClasses = detectDefaultConfigurationClasses(ExplicitConfigTestCase.class);
53+
assertNotNull(configClasses);
54+
assertArrayEquals(new Class<?>[] { ExplicitConfigTestCase.Config.class }, configClasses);
55+
}
56+
57+
@Test
58+
public void detectDefaultConfigurationClassesWithConfigurationMetaAnnotation() {
59+
Class<?>[] configClasses = detectDefaultConfigurationClasses(MetaAnnotatedConfigTestCase.class);
60+
assertNotNull(configClasses);
61+
assertArrayEquals(new Class<?>[] { MetaAnnotatedConfigTestCase.Config.class }, configClasses);
62+
}
63+
64+
65+
private static class NoConfigTestCase {
66+
67+
}
68+
69+
private static class ExplicitConfigTestCase {
70+
71+
@Configuration
72+
static class Config {
73+
}
74+
}
75+
76+
@Configuration
77+
@Retention(RetentionPolicy.RUNTIME)
78+
@Target(ElementType.TYPE)
79+
private static @interface MetaConfig {
80+
}
81+
82+
private static class MetaAnnotatedConfigTestCase {
83+
84+
@MetaConfig
85+
static class Config {
86+
}
87+
}
88+
89+
}

0 commit comments

Comments
 (0)