Skip to content

Commit 3dc7047

Browse files
committed
[Java8] Replace ConstantPoolTypeIntrospector with TypeResolver
To determine which argument types a lambda function requires we created a ConstantPoolTypeIntrospector. However it has never functioned quite correctly (#937, #1140, #957), was prone to breaking (#912, #914) and hasn't been tested much (#1048). It is important to understand that while we will get a properly functioning and tested replacement, TypeResolver uses the same ConstantPool and thus has the same potential to break. However because TypeResolver is used by a much larger audience I expect these problems to be shallow. Because this change the interface of Java8StepDefinition it made sense to refactor all the Java8 related stuff out of cucumber-java. This will make it easier in the future to add things like KotlinStepDefintions without creating a separate KotlinBackend. Related issues: - #912 - #914 - #937 - #957 - #1140 - #1048 - #1140 Closes #937 Closes #1048
1 parent 9d97735 commit 3dc7047

23 files changed

+204
-335
lines changed

java/pom.xml

-11
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
<parent>
55
<groupId>io.cucumber</groupId>
66
<artifactId>cucumber-jvm</artifactId>
7-
<relativePath>../pom.xml</relativePath>
87
<version>2.0.0-SNAPSHOT</version>
98
</parent>
109

@@ -17,16 +16,6 @@
1716
<groupId>io.cucumber</groupId>
1817
<artifactId>cucumber-core</artifactId>
1918
</dependency>
20-
<dependency>
21-
<groupId>io.cucumber</groupId>
22-
<artifactId>cucumber-jvm-deps</artifactId>
23-
<scope>provided</scope>
24-
</dependency>
25-
<dependency>
26-
<groupId>io.cucumber</groupId>
27-
<artifactId>gherkin</artifactId>
28-
<scope>provided</scope>
29-
</dependency>
3019

3120
<dependency>
3221
<groupId>io.cucumber</groupId>

java/src/main/java/cucumber/runtime/java/JavaBackend.java

+27-39
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
package cucumber.runtime.java;
22

3+
import static cucumber.runtime.io.MultiLoader.packageName;
4+
import static cucumber.runtime.java.ObjectFactoryLoader.loadObjectFactory;
5+
import static java.lang.Thread.currentThread;
6+
37
import cucumber.api.java.After;
48
import cucumber.api.java.Before;
59
import cucumber.api.java.ObjectFactory;
610
import cucumber.api.java8.GlueBase;
7-
import cucumber.api.java8.HookBody;
8-
import cucumber.api.java8.HookNoArgsBody;
9-
import cucumber.api.java8.StepdefBody;
1011
import cucumber.runtime.Backend;
1112
import cucumber.runtime.ClassFinder;
1213
import cucumber.runtime.CucumberException;
1314
import cucumber.runtime.DuplicateStepDefinitionException;
1415
import cucumber.runtime.Env;
1516
import cucumber.runtime.Glue;
17+
import cucumber.runtime.HookDefinition;
18+
import cucumber.runtime.StepDefinition;
1619
import cucumber.runtime.UnreportedStepExecutor;
1720
import cucumber.runtime.Utils;
1821
import cucumber.runtime.io.MultiLoader;
@@ -30,14 +33,12 @@
3033
import java.util.List;
3134
import java.util.regex.Pattern;
3235

33-
import static cucumber.runtime.io.MultiLoader.packageName;
34-
3536
public class JavaBackend implements Backend {
3637
public static final ThreadLocal<JavaBackend> INSTANCE = new ThreadLocal<JavaBackend>();
3738
private final SnippetGenerator snippetGenerator = new SnippetGenerator(createSnippet());
3839

3940
private Snippet createSnippet() {
40-
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
41+
ClassLoader classLoader = currentThread().getContextClassLoader();
4142
try {
4243
classLoader.loadClass("cucumber.runtime.java8.LambdaGlueBase");
4344
return new Java8Snippet();
@@ -59,24 +60,25 @@ private Snippet createSnippet() {
5960
* @param resourceLoader
6061
*/
6162
public JavaBackend(ResourceLoader resourceLoader) {
62-
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
63-
classFinder = new ResourceLoaderClassFinder(resourceLoader, classLoader);
64-
methodScanner = new MethodScanner(classFinder);
65-
objectFactory = ObjectFactoryLoader.loadObjectFactory(classFinder, Env.INSTANCE.get(ObjectFactory.class.getName()));
63+
this(new ResourceLoaderClassFinder(resourceLoader, currentThread().getContextClassLoader()));
64+
}
65+
66+
private JavaBackend(ClassFinder classFinder) {
67+
this(loadObjectFactory(classFinder, Env.INSTANCE.get(ObjectFactory.class.getName())), classFinder);
6668
}
6769

6870
public JavaBackend(ObjectFactory objectFactory) {
69-
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
70-
ResourceLoader resourceLoader = new MultiLoader(classLoader);
71-
classFinder = new ResourceLoaderClassFinder(resourceLoader, classLoader);
72-
methodScanner = new MethodScanner(classFinder);
73-
this.objectFactory = objectFactory;
71+
this(objectFactory, new MultiLoader(currentThread().getContextClassLoader()));
72+
}
73+
74+
private JavaBackend(ObjectFactory objectFactory, ResourceLoader resourceLoader) {
75+
this(objectFactory, new ResourceLoaderClassFinder(resourceLoader, currentThread().getContextClassLoader()));
7476
}
7577

7678
public JavaBackend(ObjectFactory objectFactory, ClassFinder classFinder) {
77-
this.objectFactory = objectFactory;
7879
this.classFinder = classFinder;
79-
methodScanner = new MethodScanner(classFinder);
80+
this.objectFactory = objectFactory;
81+
this.methodScanner = new MethodScanner(classFinder);
8082
}
8183

8284
@Override
@@ -157,44 +159,30 @@ void addStepDefinition(Annotation annotation, Method method) {
157159
}
158160
}
159161

160-
public void addStepDefinition(String regexp, long timeoutMillis, StepdefBody body, TypeIntrospector typeIntrospector) {
161-
try {
162-
glue.addStepDefinition(new Java8StepDefinition(Pattern.compile(regexp), timeoutMillis, body, typeIntrospector));
163-
} catch (CucumberException e) {
164-
throw e;
165-
} catch (Exception e) {
166-
throw new CucumberException(e);
167-
}
162+
public void addStepDefinition(StepDefinition stepDefinition) {
163+
glue.addStepDefinition(stepDefinition);
168164
}
169165

170166
void addHook(Annotation annotation, Method method) {
171167
if (objectFactory.addClass(method.getDeclaringClass())) {
172168
if (annotation.annotationType().equals(Before.class)) {
173169
String[] tagExpressions = ((Before) annotation).value();
174170
long timeout = ((Before) annotation).timeout();
175-
glue.addBeforeHook(new JavaHookDefinition(method, tagExpressions, ((Before) annotation).order(), timeout, objectFactory));
171+
addBeforeHookDefinition(new JavaHookDefinition(method, tagExpressions, ((Before) annotation).order(), timeout, objectFactory));
176172
} else {
177173
String[] tagExpressions = ((After) annotation).value();
178174
long timeout = ((After) annotation).timeout();
179-
glue.addAfterHook(new JavaHookDefinition(method, tagExpressions, ((After) annotation).order(), timeout, objectFactory));
175+
addAfterHookDefinition(new JavaHookDefinition(method, tagExpressions, ((After) annotation).order(), timeout, objectFactory));
180176
}
181177
}
182178
}
183179

184-
public void addBeforeHookDefinition(String[] tagExpressions, long timeoutMillis, int order, HookBody body) {
185-
glue.addBeforeHook(new Java8HookDefinition(tagExpressions, order, timeoutMillis, body));
186-
}
187-
188-
public void addAfterHookDefinition(String[] tagExpressions, long timeoutMillis, int order, HookBody body) {
189-
glue.addAfterHook(new Java8HookDefinition(tagExpressions, order, timeoutMillis, body));
190-
}
191-
192-
public void addBeforeHookDefinition(String[] tagExpressions, long timeoutMillis, int order, HookNoArgsBody body) {
193-
glue.addBeforeHook(new Java8HookDefinition(tagExpressions, order, timeoutMillis, body));
180+
public void addBeforeHookDefinition(HookDefinition beforeHook) {
181+
glue.addBeforeHook(beforeHook);
194182
}
195183

196-
public void addAfterHookDefinition(String[] tagExpressions, long timeoutMillis, int order, HookNoArgsBody body) {
197-
glue.addAfterHook(new Java8HookDefinition(tagExpressions, order, timeoutMillis, body));
184+
public void addAfterHookDefinition(HookDefinition afterHook) {
185+
glue.addAfterHook(afterHook);
198186
}
199187

200188
private Pattern pattern(Annotation annotation) throws Throwable {

java/src/main/java/cucumber/runtime/java/TypeIntrospector.java

-9
This file was deleted.

java/src/test/java/cucumber/runtime/java/JavaHookTest.java

-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import cucumber.runtime.Glue;
88
import cucumber.runtime.HookDefinition;
99
import cucumber.runtime.RuntimeGlue;
10-
import cucumber.runtime.UndefinedStepsTracker;
1110
import cucumber.runtime.xstream.LocalizedXStreams;
1211
import gherkin.pickles.PickleLocation;
1312
import gherkin.pickles.PickleTag;

java/src/test/java/cucumber/runtime/java/java8test/AnonInnerClassStepdefs.java

-20
This file was deleted.

java/src/test/java/cucumber/runtime/java/java8test/RunCukesTest.java

-10
This file was deleted.

java8/pom.xml

+4
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
<groupId>io.cucumber</groupId>
1818
<artifactId>cucumber-java</artifactId>
1919
</dependency>
20+
<dependency>
21+
<groupId>net.jodah</groupId>
22+
<artifactId>typetools</artifactId>
23+
</dependency>
2024

2125
<dependency>
2226
<groupId>io.cucumber</groupId>

java8/src/main/code_generator/I18n.java8.txt

+15-6
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,37 @@
11
package cucumber.api.java8;
22

3-
import cucumber.runtime.java8.ConstantPoolTypeIntrospector;
4-
import cucumber.runtime.java8.LambdaGlueBase;
53
import cucumber.runtime.java.JavaBackend;
4+
import cucumber.runtime.java8.Java8StepDefinition;
5+
import cucumber.runtime.java8.LambdaGlueBase;
66

77
public interface ${className} extends LambdaGlueBase {
88
<% i18n.stepKeywords.findAll { !it.contains('*') && !it.matches("^\\d.*") }.sort().unique().each { kw -> %>
99
default void ${java.text.Normalizer.normalize(kw.replaceAll("[\\s',!]", ""), java.text.Normalizer.Form.NFC)}(final String regexp, final StepdefBody.A0 body) {
10-
JavaBackend.INSTANCE.get().addStepDefinition(regexp, 0, body, ConstantPoolTypeIntrospector.INSTANCE);
10+
JavaBackend.INSTANCE.get().addStepDefinition(
11+
new Java8StepDefinition(regexp, 0, StepdefBody.A0.class, body)
12+
);
1113
}
1214

1315
default void ${java.text.Normalizer.normalize(kw.replaceAll("[\\s',!]", ""), java.text.Normalizer.Form.NFC)}(final String regexp, final long timeoutMillis, final StepdefBody.A0 body) {
14-
JavaBackend.INSTANCE.get().addStepDefinition(regexp, timeoutMillis, body, ConstantPoolTypeIntrospector.INSTANCE);
16+
JavaBackend.INSTANCE.get().addStepDefinition(
17+
new Java8StepDefinition(regexp, timeoutMillis, StepdefBody.A0.class, body)
18+
);
1519
}
1620
<% (1..9).each { arity ->
1721
def ts = (1..arity).collect { n -> "T"+n }
1822
def genericSignature = ts.join(",") %>
1923

2024
default <${genericSignature}> void ${java.text.Normalizer.normalize(kw.replaceAll("[\\s',!]", ""), java.text.Normalizer.Form.NFC)}(final String regexp, final StepdefBody.A${arity}<${genericSignature}> body) {
21-
JavaBackend.INSTANCE.get().addStepDefinition(regexp, 0, body, ConstantPoolTypeIntrospector.INSTANCE);
25+
JavaBackend.INSTANCE.get().addStepDefinition(
26+
new Java8StepDefinition(regexp, 0, StepdefBody.A${arity}.class, body)
27+
);
28+
2229
}
2330

2431
default <${genericSignature}> void ${java.text.Normalizer.normalize(kw.replaceAll("[\\s',!]", ""), java.text.Normalizer.Form.NFC)}(final String regexp, final long timeoutMillis, final StepdefBody.A${arity}<${genericSignature}> body) {
25-
JavaBackend.INSTANCE.get().addStepDefinition(regexp, timeoutMillis, body, ConstantPoolTypeIntrospector.INSTANCE);
32+
JavaBackend.INSTANCE.get().addStepDefinition(
33+
new Java8StepDefinition(regexp, timeoutMillis, StepdefBody.A${arity}.class, body)
34+
);
2635
}
2736
<% } %>
2837
<% } %>

java8/src/main/java/cucumber/runtime/java8/ConstantPoolTypeIntrospector.java

-102
This file was deleted.

0 commit comments

Comments
 (0)