1
1
package cucumber .runtime .java .spring ;
2
2
3
+ import static java .util .Arrays .asList ;
3
4
import static org .springframework .test .context .FixBootstrapUtils .createBootstrapContext ;
4
5
import static org .springframework .test .context .FixBootstrapUtils .resolveTestContextBootstrapper ;
5
6
14
15
import org .springframework .context .support .ClassPathXmlApplicationContext ;
15
16
import org .springframework .context .support .GenericApplicationContext ;
16
17
import org .springframework .stereotype .Component ;
18
+ import org .springframework .test .context .BootstrapWith ;
17
19
import org .springframework .test .context .ContextConfiguration ;
18
20
import org .springframework .test .context .ContextHierarchy ;
19
21
import org .springframework .test .context .TestContextManager ;
20
22
21
23
import java .lang .annotation .Annotation ;
22
24
import java .util .Collection ;
25
+ import java .util .Collections ;
23
26
import java .util .HashSet ;
24
27
import java .util .Set ;
25
28
import java .util .Stack ;
26
29
27
30
/**
28
31
* Spring based implementation of ObjectFactory.
29
- * <p/>
30
32
* <p>
33
+ * Application beans are accessible from the step definitions using autowiring
34
+ * (with annotations).
35
+ * <p>
36
+ * SpringFactory uses TestContextManager to manage the spring context. The step definitions are added to the
37
+ * TestContextManagers context and the context is reloaded for each scenario.
38
+ * <p>
39
+ * The spring context can be configured by:
31
40
* <ul>
32
- * <li>It uses TestContextManager to manage the spring context.
33
- * Configuration via: @{@link ContextConfiguration} or @{@link ContextHierarchy}
34
- * At least one step definition class needs to have a @ContextConfiguration
35
- * or @ContextHierarchy annotation. If more that one step definition class has such
36
- * an annotation, the annotations must be equal on the different step definition
37
- * classes. If no step definition class with @ContextConfiguration or @ContextHierarchy
38
- * is found, it will try to load cucumber.xml from the classpath.
39
- * </li>
40
- * <li>The step definitions class with @ContextConfiguration or @ContextHierarchy
41
- * annotation, may also have a @{@link org.springframework.test.context.web.WebAppConfiguration}
41
+ * <li>Annotating one step definition with: @{@link ContextConfiguration}, @{@link ContextHierarchy}
42
+ * or @{@link BootstrapWith}. This step definition can also be annotated
43
+ * with @{@link org.springframework.test.context.web.WebAppConfiguration}
42
44
* or @{@link org.springframework.test.annotation.DirtiesContext} annotation.
45
+ * <p>
46
+ * If more that one step definition class has such an annotation, the annotations must be equal on
47
+ * the different step definition. <b>Deprecation warning:</b> Annotating multiple step definitions is deprecated.
43
48
* </li>
44
- * <li>The step definitions are added to the TestContextManagers context and
45
- * is reloaded for each scenario.</li>
46
- * <li>Step definitions should not be annotated with @{@link Component} or
47
- * other annotations that mark it as eligible for detection by classpath scanning.</li>
48
- * <li>When a step definition class is annotated by @Component or an annotation that has the @Component stereotype an
49
- * exception will be thrown</li>
50
- * </li>
49
+ * <li>If no step definition class with @ContextConfiguration or @ContextHierarchy
50
+ * is found, it will try to load cucumber.xml from the classpath.</li>
51
51
* </ul>
52
- * <p/>
53
52
* <p>
54
- * Application beans are accessible from the step definitions using autowiring
55
- * (with annotations).
56
- * </p>
53
+ * Notes:
54
+ * <ul>
55
+ * <li>
56
+ * Step definitions should not be annotated with @{@link Component} or other annotations that mark it as eligible for
57
+ * detection by classpath scanning. When a step definition class is annotated by @Component or an annotation that has
58
+ * the @Component stereotype an exception will be thrown
59
+ * </li>
60
+ * <li>
61
+ * If more that one step definition class is used to configure the spring context, the annotations must be equal
62
+ * on the different step definition. Please note that doing so is deprecated.
63
+ * </li>
64
+ * </ul>
57
65
*/
58
66
public class SpringFactory implements ObjectFactory {
59
67
@@ -85,7 +93,7 @@ public boolean addClass(final Class<?> stepClass) {
85
93
86
94
private static void checkNoComponentAnnotations (Class <?> type ) {
87
95
for (Annotation annotation : type .getAnnotations ()) {
88
- if (hasComponentStereoType (annotation )) {
96
+ if (hasComponentAnnotation (annotation )) {
89
97
throw new CucumberException (String .format ("" +
90
98
"Glue class %1$s was annotated with @%2$s; marking it as a candidate for auto-detection by " +
91
99
"Spring. Glue classes are detected and registered by Cucumber. Auto-detection of glue classes by " +
@@ -96,14 +104,18 @@ private static void checkNoComponentAnnotations(Class<?> type) {
96
104
}
97
105
}
98
106
99
- private static boolean hasComponentStereoType (Annotation annotation ) {
107
+ private static boolean hasComponentAnnotation (Annotation annotation ) {
108
+ return hasAnnotation (annotation , Collections .<Class <? extends Annotation >>singleton (Component .class ));
109
+ }
110
+
111
+ private static boolean hasAnnotation (Annotation annotation , Collection <Class <? extends Annotation >> desired ) {
100
112
Set <Class <? extends Annotation >> seen = new HashSet <Class <? extends Annotation >>();
101
113
Stack <Class <? extends Annotation >> toCheck = new Stack <Class <? extends Annotation >>();
102
114
toCheck .add (annotation .annotationType ());
103
115
104
116
while (!toCheck .isEmpty ()) {
105
117
Class <? extends Annotation > annotationType = toCheck .pop ();
106
- if (Component . class . equals (annotationType )) {
118
+ if (desired . contains (annotationType )) {
107
119
return true ;
108
120
}
109
121
@@ -240,20 +252,20 @@ public <T> T getInstance(final Class<T> type) {
240
252
}
241
253
}
242
254
243
- private boolean dependsOnSpringContext (Class <?> type ) {
244
- boolean hasStandardAnnotations = annotatedWithSupportedSpringRootTestAnnotations ( type );
245
-
246
- if ( hasStandardAnnotations ) {
247
- return true ;
255
+ private static boolean dependsOnSpringContext (Class <?> type ) {
256
+ for ( Annotation annotation : type . getAnnotations ()) {
257
+ if ( annotatedWithSupportedSpringRootTestAnnotations ( annotation )){
258
+ return true ;
259
+ }
248
260
}
249
-
250
- final Annotation [] annotations = type .getDeclaredAnnotations ();
251
- return (annotations .length == 1 ) && annotatedWithSupportedSpringRootTestAnnotations (annotations [0 ].annotationType ());
261
+ return false ;
252
262
}
253
263
254
- private boolean annotatedWithSupportedSpringRootTestAnnotations (Class <?> type ) {
255
- return type .isAnnotationPresent (ContextConfiguration .class )
256
- || type .isAnnotationPresent (ContextHierarchy .class );
264
+ private static boolean annotatedWithSupportedSpringRootTestAnnotations (Annotation type ) {
265
+ return hasAnnotation (type , asList (
266
+ ContextConfiguration .class ,
267
+ ContextHierarchy .class ,
268
+ BootstrapWith .class ));
257
269
}
258
270
}
259
271
0 commit comments