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
13
14
import org .springframework .context .ConfigurableApplicationContext ;
14
15
import org .springframework .context .support .ClassPathXmlApplicationContext ;
15
16
import org .springframework .context .support .GenericApplicationContext ;
17
+ import org .springframework .stereotype .Component ;
18
+ import org .springframework .stereotype .Controller ;
19
+ import org .springframework .stereotype .Repository ;
20
+ import org .springframework .stereotype .Service ;
16
21
import org .springframework .test .context .ContextConfiguration ;
17
22
import org .springframework .test .context .ContextHierarchy ;
18
23
import org .springframework .test .context .TestContextManager ;
19
24
20
25
import java .lang .annotation .Annotation ;
21
26
import java .util .Collection ;
22
27
import java .util .HashSet ;
28
+ import java .util .List ;
23
29
24
30
/**
25
31
* Spring based implementation of ObjectFactory.
26
32
* <p/>
27
33
* <p>
28
34
* <ul>
29
35
* <li>It uses TestContextManager to manage the spring context.
30
- * Configuration via: @ContextConfiguration or @ContextHierarcy
31
- * At least on step definition class needs to have a @ContextConfiguration or
32
- * @ContextHierarchy annotation. If more that one step definition class has such
36
+ * Configuration via: @{@link ContextConfiguration} or @{@link ContextHierarchy}
37
+ * At least one step definition class needs to have a @ContextConfiguration
38
+ * or @ContextHierarchy annotation. If more that one step definition class has such
33
39
* an annotation, the annotations must be equal on the different step definition
34
- * classes. If no step definition class with @ContextConfiguration or
35
- * @ContextHierarcy is found, it will try to load cucumber.xml from the classpath.
40
+ * classes. If no step definition class with @ContextConfiguration or @ContextHierarchy
41
+ * is found, it will try to load cucumber.xml from the classpath.
36
42
* </li>
37
43
* <li>The step definitions class with @ContextConfiguration or @ContextHierarchy
38
- * annotation, may also have a @WebAppConfiguration or @DirtiesContext annotation.
44
+ * annotation, may also have a @{@link org.springframework.test.context.web.WebAppConfiguration}
45
+ * or @{@link org.springframework.test.annotation.DirtiesContext} annotation.
39
46
* </li>
40
47
* <li>The step definitions added to the TestContextManagers context and
41
48
* is reloaded for each scenario.</li>
49
+ * <li>Step definition classes should not be annotated with @{@link Component} or
50
+ * other annotations that marks it as eligible for detection by classpath scanning.</li>
51
+ * <li>When a step definition class is annotated with @Component, @{@link Controller}, @{@link Repository}
52
+ * or @{@link Service} an exception will be thrown.</li>
53
+ * </li>
42
54
* </ul>
43
- * </p>
44
55
* <p/>
45
56
* <p>
46
57
* Application beans are accessible from the step definitions using autowiring
49
60
*/
50
61
public class SpringFactory implements ObjectFactory {
51
62
63
+ private static final List <Class <? extends Annotation >> componentStereoTypes = asList (Component .class , Controller .class , Repository .class , Service .class );
64
+
52
65
private ConfigurableListableBeanFactory beanFactory ;
53
66
private CucumberTestContextManager testContextManager ;
54
67
@@ -61,6 +74,7 @@ public SpringFactory() {
61
74
@ Override
62
75
public boolean addClass (final Class <?> stepClass ) {
63
76
if (!stepClasses .contains (stepClass )) {
77
+ checkNoComponentAnnotations (stepClass );
64
78
if (dependsOnSpringContext (stepClass )) {
65
79
if (stepClassWithSpringContext == null ) {
66
80
stepClassWithSpringContext = stepClass ;
@@ -73,6 +87,20 @@ public boolean addClass(final Class<?> stepClass) {
73
87
return true ;
74
88
}
75
89
90
+ private void checkNoComponentAnnotations (Class <?> type ) {
91
+ for (Class <? extends Annotation > stereoType : componentStereoTypes ) {
92
+ if (type .isAnnotationPresent (stereoType )) {
93
+ throw new CucumberException (String .format ("" +
94
+ "Glue class %1$s was annotated with @%2$s; marking it as a candidate for auto-detection by " +
95
+ "Spring. Glue classes are detected and registered by Cucumber. Auto-detection of glue classes by " +
96
+ "spring may lead to duplicate bean definitions. Please remove the @%2$s annotation" ,
97
+ type .getName (),
98
+ stereoType .getSimpleName ()));
99
+ }
100
+ }
101
+ }
102
+
103
+
76
104
private void checkAnnotationsEqual (Class <?> stepClassWithSpringContext , Class <?> stepClass ) {
77
105
Annotation [] annotations1 = stepClassWithSpringContext .getAnnotations ();
78
106
Annotation [] annotations2 = stepClass .getAnnotations ();
0 commit comments