Skip to content

Commit 6c704c3

Browse files
committed
[Java] Remove circular dependency between method scanner and backend
1 parent 09cc6b7 commit 6c704c3

13 files changed

+381
-206
lines changed

java/src/main/groovy/annotation.java.gsp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package io.cucumber.java.${lang};
22

3-
import io.cucumber.java.StepDefAnnotation;
4-
import io.cucumber.java.StepDefAnnotations;
3+
import io.cucumber.java.StepDefinitionAnnotations;
4+
import io.cucumber.java.StepDefinitionAnnotation;
55

66
import org.apiguardian.api.API;
77

@@ -31,7 +31,7 @@ import java.lang.annotation.Target;
3131
*/
3232
@Retention(RetentionPolicy.RUNTIME)
3333
@Target(ElementType.METHOD)
34-
@StepDefAnnotation
34+
@StepDefinitionAnnotation
3535
@Documented
3636
@Repeatable(${kw}.${kw}s.class)
3737
@API(status = API.Status.STABLE)
@@ -63,7 +63,7 @@ public @interface ${kw} {
6363
*/
6464
@Target(ElementType.METHOD)
6565
@Retention(RetentionPolicy.RUNTIME)
66-
@StepDefAnnotations
66+
@StepDefinitionAnnotations
6767
@Documented
6868
@interface ${kw}s {
6969
${kw}[] value();
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package io.cucumber.java;
2+
3+
import io.cucumber.core.backend.Glue;
4+
import io.cucumber.core.backend.Lookup;
5+
import io.cucumber.core.runtime.Invoker;
6+
7+
import java.lang.annotation.Annotation;
8+
import java.lang.reflect.Method;
9+
10+
final class GlueAdaptor {
11+
12+
private final Lookup lookup;
13+
private final Glue glue;
14+
15+
GlueAdaptor(Lookup lookup, Glue glue) {
16+
this.lookup = lookup;
17+
this.glue = glue;
18+
}
19+
20+
void addDefinition(Method method, Annotation annotation) {
21+
if (annotation.annotationType().getAnnotation(StepDefinitionAnnotation.class) != null) {
22+
String expression = expression(annotation);
23+
long timeoutMillis = timeoutMillis(annotation);
24+
glue.addStepDefinition(new JavaStepDefinition(method, expression, timeoutMillis, lookup));
25+
} else if (annotation.annotationType().equals(Before.class)) {
26+
Before before = (Before) annotation;
27+
String tagExpression = before.value();
28+
long timeout = before.timeout();
29+
glue.addBeforeHook(new JavaHookDefinition(method, tagExpression, before.order(), timeout, lookup));
30+
} else if (annotation.annotationType().equals(After.class)) {
31+
After after = (After) annotation;
32+
String tagExpression = after.value();
33+
long timeout = after.timeout();
34+
glue.addAfterHook(new JavaHookDefinition(method, tagExpression, after.order(), timeout, lookup));
35+
} else if (annotation.annotationType().equals(BeforeStep.class)) {
36+
BeforeStep beforeStep = (BeforeStep) annotation;
37+
String tagExpression = beforeStep.value();
38+
long timeout = beforeStep.timeout();
39+
glue.addBeforeStepHook(new JavaHookDefinition(method, tagExpression, beforeStep.order(), timeout, lookup));
40+
} else if (annotation.annotationType().equals(AfterStep.class)) {
41+
AfterStep afterStep = (AfterStep) annotation;
42+
String tagExpression = afterStep.value();
43+
long timeout = afterStep.timeout();
44+
glue.addAfterStepHook(new JavaHookDefinition(method, tagExpression, afterStep.order(), timeout, lookup));
45+
} else if (annotation.annotationType().equals(ParameterType.class)) {
46+
ParameterType parameterType = (ParameterType) annotation;
47+
String pattern = parameterType.value();
48+
String name = parameterType.name();
49+
boolean useForSnippets = parameterType.useForSnippets();
50+
boolean preferForRegexMatch = parameterType.preferForRegexMatch();
51+
glue.addParameterType(new JavaParameterTypeDefinition(name, pattern, method, useForSnippets, preferForRegexMatch, lookup));
52+
} else if (annotation.annotationType().equals(DataTableType.class)) {
53+
glue.addDataTableType(new JavaDataTableTypeDefinition(method, lookup));
54+
} else if (annotation.annotationType().equals(DefaultParameterTransformer.class)) {
55+
glue.addDefaultParameterTransformer(new JavaDefaultParameterTransformerDefinition(method, lookup));
56+
} else if (annotation.annotationType().equals(DefaultDataTableEntryTransformer.class)) {
57+
glue.addDefaultDataTableEntryTransformer(new JavaDefaultDataTableEntryTransformerDefinition(method, lookup));
58+
} else if (annotation.annotationType().equals(DefaultDataTableCellTransformer.class)) {
59+
glue.addDefaultDataTableCellTransformer(new JavaDefaultDataTableCellTransformerDefinition(method, lookup));
60+
}
61+
}
62+
63+
private static String expression(Annotation annotation) {
64+
try {
65+
Method expressionMethod = annotation.getClass().getMethod("value");
66+
return (String) Invoker.invoke(annotation, expressionMethod, 0);
67+
} catch (Throwable e) {
68+
throw new IllegalStateException(e);
69+
}
70+
}
71+
72+
private static long timeoutMillis(Annotation annotation) {
73+
try {
74+
Method regexpMethod = annotation.getClass().getMethod("timeout");
75+
return (Long) Invoker.invoke(annotation, regexpMethod, 0);
76+
} catch (Throwable throwable) {
77+
throw new IllegalStateException(throwable);
78+
}
79+
}
80+
81+
82+
}

java/src/main/java/io/cucumber/java/InvalidMethodException.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,4 @@ static InvalidMethodException createInvalidMethodException(Method method, Class<
1616
+ glueCodeClass + " extends " + method.getDeclaringClass());
1717
}
1818

19-
static InvalidMethodException createMethodDeclaringClassNotAssignableFromGlue(Method method, Class<?> glueCodeClass) {
20-
return new InvalidMethodException(method.getDeclaringClass() + " isn't assignable from " + glueCodeClass);
21-
}
22-
2319
}

java/src/main/java/io/cucumber/java/JavaBackend.java

Lines changed: 11 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,11 @@
44
import io.cucumber.core.backend.Container;
55
import io.cucumber.core.backend.Glue;
66
import io.cucumber.core.backend.Lookup;
7-
import io.cucumber.core.exception.CucumberException;
87
import io.cucumber.core.io.ClassFinder;
98
import io.cucumber.core.io.ResourceLoader;
109
import io.cucumber.core.io.ResourceLoaderClassFinder;
11-
import io.cucumber.core.runtime.Invoker;
1210
import io.cucumber.core.snippets.Snippet;
1311

14-
import java.lang.annotation.Annotation;
15-
import java.lang.reflect.Method;
1612
import java.net.URI;
1713
import java.util.List;
1814

@@ -22,9 +18,7 @@ final class JavaBackend implements Backend {
2218

2319
private final Lookup lookup;
2420
private final Container container;
25-
26-
private final MethodScanner methodScanner;
27-
private Glue glue;
21+
private final ClassFinder classFinder;
2822

2923
JavaBackend(Lookup lookup, Container container, ResourceLoader resourceLoader) {
3024
this(lookup, container, new ResourceLoaderClassFinder(resourceLoader, currentThread().getContextClassLoader()));
@@ -33,14 +27,20 @@ final class JavaBackend implements Backend {
3327
JavaBackend(Lookup lookup, Container container, ClassFinder classFinder) {
3428
this.lookup = lookup;
3529
this.container = container;
36-
this.methodScanner = new MethodScanner(classFinder);
30+
this.classFinder = classFinder;
3731
}
3832

3933
@Override
4034
public void loadGlue(Glue glue, List<URI> gluePaths) {
41-
this.glue = glue;
42-
// Scan for Java7 style glue (annotated methods)
43-
methodScanner.scan(this, gluePaths);
35+
GlueAdaptor glueAdaptor = new GlueAdaptor(lookup, glue);
36+
for (URI gluePath : gluePaths) {
37+
for (Class<?> glueCodeClass : classFinder.getDescendants(Object.class, gluePath)) {
38+
MethodScanner.scan(glueCodeClass, (method, annotation) -> {
39+
container.addClass(method.getDeclaringClass());
40+
glueAdaptor.addDefinition(method, annotation);
41+
});
42+
}
43+
}
4444
}
4545

4646
@Override
@@ -57,71 +57,4 @@ public void disposeWorld() {
5757
public Snippet getSnippet() {
5858
return new JavaSnippet();
5959
}
60-
61-
void addStepDefinition(Annotation annotation, Method method) {
62-
String expression = expression(annotation);
63-
long timeoutMillis = timeoutMillis(annotation);
64-
container.addClass(method.getDeclaringClass());
65-
glue.addStepDefinition(new JavaStepDefinition(method, expression, timeoutMillis, lookup));
66-
}
67-
68-
void addHook(Annotation annotation, Method method) {
69-
if (container.addClass(method.getDeclaringClass())) {
70-
if (annotation.annotationType().equals(Before.class)) {
71-
Before before = (Before) annotation;
72-
String tagExpression = before.value();
73-
long timeout = before.timeout();
74-
glue.addBeforeHook(new JavaHookDefinition(method, tagExpression, before.order(), timeout, lookup));
75-
} else if (annotation.annotationType().equals(After.class)) {
76-
After after = (After) annotation;
77-
String tagExpression = after.value();
78-
long timeout = after.timeout();
79-
glue.addAfterHook(new JavaHookDefinition(method, tagExpression, after.order(), timeout, lookup));
80-
} else if (annotation.annotationType().equals(BeforeStep.class)) {
81-
BeforeStep beforeStep = (BeforeStep) annotation;
82-
String tagExpression = beforeStep.value();
83-
long timeout = beforeStep.timeout();
84-
glue.addBeforeStepHook(new JavaHookDefinition(method, tagExpression, beforeStep.order(), timeout, lookup));
85-
} else if (annotation.annotationType().equals(AfterStep.class)) {
86-
AfterStep afterStep = (AfterStep) annotation;
87-
String tagExpression = afterStep.value();
88-
long timeout = afterStep.timeout();
89-
glue.addAfterStepHook(new JavaHookDefinition(method, tagExpression, afterStep.order(), timeout, lookup));
90-
} else if (annotation.annotationType().equals(ParameterType.class)) {
91-
ParameterType parameterType = (ParameterType) annotation;
92-
String pattern = parameterType.value();
93-
String name = parameterType.name();
94-
boolean useForSnippets = parameterType.useForSnippets();
95-
boolean preferForRegexMatch = parameterType.preferForRegexMatch();
96-
glue.addParameterType(new JavaParameterTypeDefinition(name, pattern, method, useForSnippets, preferForRegexMatch, lookup));
97-
} else if (annotation.annotationType().equals(DataTableType.class)) {
98-
glue.addDataTableType(new JavaDataTableTypeDefinition(method, lookup));
99-
} else if (annotation.annotationType().equals(DefaultParameterTransformer.class)) {
100-
glue.addDefaultParameterTransformer(new JavaDefaultParameterTransformerDefinition(method, lookup));
101-
} else if (annotation.annotationType().equals(DefaultDataTableEntryTransformer.class)) {
102-
glue.addDefaultDataTableEntryTransformer(new JavaDefaultDataTableEntryTransformerDefinition(method, lookup));
103-
} else if (annotation.annotationType().equals(DefaultDataTableCellTransformer.class)) {
104-
glue.addDefaultDataTableCellTransformer(new JavaDefaultDataTableCellTransformerDefinition(method, lookup));
105-
}
106-
}
107-
}
108-
109-
private String expression(Annotation annotation) {
110-
try {
111-
Method expressionMethod = annotation.getClass().getMethod("value");
112-
return (String) Invoker.invoke(annotation, expressionMethod, 0);
113-
} catch (Throwable e) {
114-
throw new CucumberException(e);
115-
}
116-
}
117-
118-
private long timeoutMillis(Annotation annotation) {
119-
try {
120-
Method regexpMethod = annotation.getClass().getMethod("timeout");
121-
return (Long) Invoker.invoke(annotation, regexpMethod, 0);
122-
} catch (Throwable throwable) {
123-
throw new CucumberException(throwable);
124-
}
125-
}
126-
12760
}

java/src/main/java/io/cucumber/java/JavaHookDefinition.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,6 @@ final class JavaHookDefinition extends AbstractGlueDefinition implements HookDef
2727
this.lookup = lookup;
2828
}
2929

30-
Method getMethod() {
31-
return method;
32-
}
33-
3430
private static Method requireValidMethod(Method method) {
3531
Class<?>[] parameterTypes = method.getParameterTypes();
3632
if (parameterTypes.length > 1) {

java/src/main/java/io/cucumber/java/JavaParameterInfo.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,4 @@ public TypeResolver getTypeResolver() {
5050
return () -> type;
5151
}
5252

53-
@Override
54-
public String toString() {
55-
return type.toString();
56-
}
57-
5853
}

0 commit comments

Comments
 (0)