Skip to content

Commit

Permalink
[Java8] Replace ConstantPoolTypeIntrospector with TypeResolver
Browse files Browse the repository at this point in the history
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
  • Loading branch information
mpkorstanje committed Jul 14, 2017
1 parent cb20ce6 commit cf553b7
Show file tree
Hide file tree
Showing 23 changed files with 202 additions and 333 deletions.
11 changes: 0 additions & 11 deletions java/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
<parent>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-jvm</artifactId>
<relativePath>../pom.xml</relativePath>
<version>2.0.0-SNAPSHOT</version>
</parent>

Expand All @@ -17,16 +16,6 @@
<groupId>io.cucumber</groupId>
<artifactId>cucumber-core</artifactId>
</dependency>
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-jvm-deps</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>gherkin</artifactId>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>io.cucumber</groupId>
Expand Down
66 changes: 27 additions & 39 deletions java/src/main/java/cucumber/runtime/java/JavaBackend.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
package cucumber.runtime.java;

import static cucumber.runtime.io.MultiLoader.packageName;
import static cucumber.runtime.java.ObjectFactoryLoader.loadObjectFactory;
import static java.lang.Thread.currentThread;

import cucumber.api.java.After;
import cucumber.api.java.Before;
import cucumber.api.java.ObjectFactory;
import cucumber.api.java8.GlueBase;
import cucumber.api.java8.HookBody;
import cucumber.api.java8.HookNoArgsBody;
import cucumber.api.java8.StepdefBody;
import cucumber.runtime.Backend;
import cucumber.runtime.ClassFinder;
import cucumber.runtime.CucumberException;
import cucumber.runtime.DuplicateStepDefinitionException;
import cucumber.runtime.Env;
import cucumber.runtime.Glue;
import cucumber.runtime.HookDefinition;
import cucumber.runtime.StepDefinition;
import cucumber.runtime.UnreportedStepExecutor;
import cucumber.runtime.Utils;
import cucumber.runtime.io.MultiLoader;
Expand All @@ -30,14 +33,12 @@
import java.util.List;
import java.util.regex.Pattern;

import static cucumber.runtime.io.MultiLoader.packageName;

public class JavaBackend implements Backend {
public static final ThreadLocal<JavaBackend> INSTANCE = new ThreadLocal<JavaBackend>();
private final SnippetGenerator snippetGenerator = new SnippetGenerator(createSnippet());

private Snippet createSnippet() {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
ClassLoader classLoader = currentThread().getContextClassLoader();
try {
classLoader.loadClass("cucumber.runtime.java8.LambdaGlueBase");
return new Java8Snippet();
Expand All @@ -59,24 +60,25 @@ private Snippet createSnippet() {
* @param resourceLoader
*/
public JavaBackend(ResourceLoader resourceLoader) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
classFinder = new ResourceLoaderClassFinder(resourceLoader, classLoader);
methodScanner = new MethodScanner(classFinder);
objectFactory = ObjectFactoryLoader.loadObjectFactory(classFinder, Env.INSTANCE.get(ObjectFactory.class.getName()));
this(new ResourceLoaderClassFinder(resourceLoader, currentThread().getContextClassLoader()));
}

private JavaBackend(ClassFinder classFinder) {
this(loadObjectFactory(classFinder, Env.INSTANCE.get(ObjectFactory.class.getName())), classFinder);
}

public JavaBackend(ObjectFactory objectFactory) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
ResourceLoader resourceLoader = new MultiLoader(classLoader);
classFinder = new ResourceLoaderClassFinder(resourceLoader, classLoader);
methodScanner = new MethodScanner(classFinder);
this.objectFactory = objectFactory;
this(objectFactory,
new ResourceLoaderClassFinder(
new MultiLoader(
currentThread().getContextClassLoader()),
currentThread().getContextClassLoader()));
}

public JavaBackend(ObjectFactory objectFactory, ClassFinder classFinder) {
this.objectFactory = objectFactory;
this.classFinder = classFinder;
methodScanner = new MethodScanner(classFinder);
this.objectFactory = objectFactory;
this.methodScanner = new MethodScanner(classFinder);
}

@Override
Expand Down Expand Up @@ -157,44 +159,30 @@ void addStepDefinition(Annotation annotation, Method method) {
}
}

public void addStepDefinition(String regexp, long timeoutMillis, StepdefBody body, TypeIntrospector typeIntrospector) {
try {
glue.addStepDefinition(new Java8StepDefinition(Pattern.compile(regexp), timeoutMillis, body, typeIntrospector));
} catch (CucumberException e) {
throw e;
} catch (Exception e) {
throw new CucumberException(e);
}
public void addStepDefinition(StepDefinition stepDefinition) {
glue.addStepDefinition(stepDefinition);
}

void addHook(Annotation annotation, Method method) {
if (objectFactory.addClass(method.getDeclaringClass())) {
if (annotation.annotationType().equals(Before.class)) {
String[] tagExpressions = ((Before) annotation).value();
long timeout = ((Before) annotation).timeout();
glue.addBeforeHook(new JavaHookDefinition(method, tagExpressions, ((Before) annotation).order(), timeout, objectFactory));
addBeforeHookDefinition(new JavaHookDefinition(method, tagExpressions, ((Before) annotation).order(), timeout, objectFactory));
} else {
String[] tagExpressions = ((After) annotation).value();
long timeout = ((After) annotation).timeout();
glue.addAfterHook(new JavaHookDefinition(method, tagExpressions, ((After) annotation).order(), timeout, objectFactory));
addAfterHookDefinition(new JavaHookDefinition(method, tagExpressions, ((After) annotation).order(), timeout, objectFactory));
}
}
}

public void addBeforeHookDefinition(String[] tagExpressions, long timeoutMillis, int order, HookBody body) {
glue.addBeforeHook(new Java8HookDefinition(tagExpressions, order, timeoutMillis, body));
}

public void addAfterHookDefinition(String[] tagExpressions, long timeoutMillis, int order, HookBody body) {
glue.addAfterHook(new Java8HookDefinition(tagExpressions, order, timeoutMillis, body));
}

public void addBeforeHookDefinition(String[] tagExpressions, long timeoutMillis, int order, HookNoArgsBody body) {
glue.addBeforeHook(new Java8HookDefinition(tagExpressions, order, timeoutMillis, body));
public void addBeforeHookDefinition(HookDefinition beforeHook) {
glue.addBeforeHook(beforeHook);
}

public void addAfterHookDefinition(String[] tagExpressions, long timeoutMillis, int order, HookNoArgsBody body) {
glue.addAfterHook(new Java8HookDefinition(tagExpressions, order, timeoutMillis, body));
public void addAfterHookDefinition(HookDefinition afterHook) {
glue.addAfterHook(afterHook);
}

private Pattern pattern(Annotation annotation) throws Throwable {
Expand Down

This file was deleted.

1 change: 0 additions & 1 deletion java/src/test/java/cucumber/runtime/java/JavaHookTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import cucumber.runtime.Glue;
import cucumber.runtime.HookDefinition;
import cucumber.runtime.RuntimeGlue;
import cucumber.runtime.UndefinedStepsTracker;
import cucumber.runtime.xstream.LocalizedXStreams;
import gherkin.pickles.PickleLocation;
import gherkin.pickles.PickleTag;
Expand Down

This file was deleted.

This file was deleted.

4 changes: 4 additions & 0 deletions java8/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
</dependency>
<dependency>
<groupId>net.jodah</groupId>
<artifactId>typetools</artifactId>
</dependency>

<dependency>
<groupId>io.cucumber</groupId>
Expand Down
21 changes: 15 additions & 6 deletions java8/src/main/code_generator/I18n.java8.txt
Original file line number Diff line number Diff line change
@@ -1,28 +1,37 @@
package cucumber.api.java8;

import cucumber.runtime.java8.ConstantPoolTypeIntrospector;
import cucumber.runtime.java8.LambdaGlueBase;
import cucumber.runtime.java.JavaBackend;
import cucumber.runtime.java8.Java8StepDefinition;
import cucumber.runtime.java8.LambdaGlueBase;

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

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

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

}

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) {
JavaBackend.INSTANCE.get().addStepDefinition(regexp, timeoutMillis, body, ConstantPoolTypeIntrospector.INSTANCE);
JavaBackend.INSTANCE.get().addStepDefinition(
new Java8StepDefinition(regexp, timeoutMillis, StepdefBody.A${arity}.class, body)
);
}
<% } %>
<% } %>
Expand Down

This file was deleted.

Loading

0 comments on commit cf553b7

Please sign in to comment.