Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kotlin and Java8 lamda parsing results in ArrayIndexOutOfBoundsException #1123

Closed
lunivore opened this issue May 15, 2017 · 5 comments
Closed

Comments

@lunivore
Copy link

I'm running with a Cucumber JVM feature file, using Java8 and PicoContainer. Here's my feature:

Feature: Full Journey

Scenario: Can load a typical JIRA csv and calculate the distribution from it

Given a typical JIRA export "/closed_only_JIRA.csv"
When I import it into Montecarluni
Then I should see the distribution
"""
6, 15, 3, 14, 2, 5, 6, 8, 5, 10, 15, 4, 2, 1
"""
When I copy it to the clipboard
Then I should be able to paste it somewhere else

Running this step in Kotlin causes an error:

import cucumber.api.java8.En

class ClipboardSteps(val world : World) : En {
    init {
        When("^I copy it to the clipboard$", {
            // Errors even without any code here 
        })
    }
}

While this Java class runs just fine:

import cucumber.api.java8.En;

public class JavaClipboardSteps implements En {

    public JavaClipboardSteps(World world) {
        When("^I copy it to the clipboard$", () -> {
            // Works just fine with code or without
        });
    }
}

This Kotlin step also runs fine, so you can see this is pretty unpredictable:

import cucumber.api.java8.En

class FileImportSteps(val world: World) : En {
    init {
        // There's a Given here

        When("^I import it into Montecarluni$", {
            // There's some code here
        })
    }
}

The Runner, for completion:

import cucumber.api.CucumberOptions
import cucumber.api.junit.Cucumber
import org.junit.runner.RunWith

@RunWith(Cucumber::class)
@CucumberOptions(
    format = arrayOf("pretty"),
    glue = arrayOf("com.lunivore.montecarluni.glue"),
    features = arrayOf("."))
class Runner {
}

Stacktrace is:

cucumber.runtime.CucumberException: java.lang.ArrayIndexOutOfBoundsException: 52

at cucumber.runtime.java.JavaBackend.addStepDefinition(JavaBackend.java:166)
at cucumber.api.java8.En.Then(En.java:280)
at com.lunivore.montecarluni.glue.DistributionSteps.<init>(DistributionSteps.kt:8)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.picocontainer.injectors.AbstractInjector.newInstance(AbstractInjector.java:145)
at org.picocontainer.injectors.ConstructorInjector$1.run(ConstructorInjector.java:342)
at org.picocontainer.injectors.AbstractInjector$ThreadLocalCyclicDependencyGuard.observe(AbstractInjector.java:270)
at org.picocontainer.injectors.ConstructorInjector.getComponentInstance(ConstructorInjector.java:364)
at org.picocontainer.injectors.AbstractInjectionFactory$LifecycleAdapter.getComponentInstance(AbstractInjectionFactory.java:56)
at org.picocontainer.behaviors.AbstractBehavior.getComponentInstance(AbstractBehavior.java:64)
at org.picocontainer.behaviors.Stored.getComponentInstance(Stored.java:91)
at org.picocontainer.DefaultPicoContainer.getInstance(DefaultPicoContainer.java:699)
at org.picocontainer.DefaultPicoContainer.getComponent(DefaultPicoContainer.java:647)
at org.picocontainer.DefaultPicoContainer.getComponent(DefaultPicoContainer.java:678)
at cucumber.runtime.java.picocontainer.PicoFactory.getInstance(PicoFactory.java:40)
at cucumber.runtime.java.JavaBackend.buildWorld(JavaBackend.java:131)
at cucumber.runtime.Runtime.buildBackendWorlds(Runtime.java:141)
at cucumber.runtime.model.CucumberScenario.run(CucumberScenario.java:38)
at cucumber.runtime.junit.ExecutionUnitRunner.run(ExecutionUnitRunner.java:102)
at cucumber.runtime.junit.FeatureRunner.runChild(FeatureRunner.java:63)
at cucumber.runtime.junit.FeatureRunner.runChild(FeatureRunner.java:18)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at cucumber.runtime.junit.FeatureRunner.run(FeatureRunner.java:70)
at cucumber.api.junit.Cucumber.runChild(Cucumber.java:95)
at cucumber.api.junit.Cucumber.runChild(Cucumber.java:38)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at cucumber.api.junit.Cucumber.run(Cucumber.java:100)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

Caused by: java.lang.ArrayIndexOutOfBoundsException: 52
at jdk.internal.org.objectweb.asm.Type.getArgumentTypes(Type.java:358)
at cucumber.runtime.java8.ConstantPoolTypeIntrospector.getGenericTypes(ConstantPoolTypeIntrospector.java:32)
at cucumber.runtime.java.Java8StepDefinition.getParameterInfos(Java8StepDefinition.java:54)
at cucumber.runtime.java.Java8StepDefinition.<init>(Java8StepDefinition.java:44)
at cucumber.runtime.java.JavaBackend.addStepDefinition(JavaBackend.java:162)
... 44 more

Other things you might want to look at:

My Github code, with Kotlin step commented out

Dan's response on Stackoverflow

I am happy to act as tester on this one if you would like.

mpkorstanje added a commit that referenced this issue Jun 3, 2017
The implementation of t he `ConstantPoolTypeIntrospector` supported:
 - Reference to a static method
 - Reference to an instance method of a particular object
 - Reference to a constructor

 But did not support:
  - Reference to an instance method of an arbitrary object of a particular type

Referencing instances methods would result in an index out of bounds exception
as  the step definition interface was expecting exactly 1 more argument then
was bound to the body. We now use this discrepancy to detect if this is an
instance method reference and include the the instance class as the first type.

Related issues:
 - #1123
 - #1126

 This fixes #1126
mpkorstanje added a commit that referenced this issue Jun 3, 2017
The implementation of t he `ConstantPoolTypeIntrospector` did not fully
support closures.

Using a closure without  scoped variables would result
in a null pointer exception.  E.g:

```java
Given("^A statement with a body expression$") { assertTrue(true) }
```

 This is resolved check if the member reference method equals the magic
 constant "INSTANCE" and return no type arguments.

Related issues:
 - #1123
 - #1126

 This fixes #1123
@mpkorstanje
Copy link
Contributor

Very interesting. Can you try building support-java-8-method-references locally and add a dependency to io.cucumber:cucumber-kotlin-java8:2.0.0-SNAPSHOT? Note that the groupId has also changed.

This should solve the problem.

mpkorstanje added a commit that referenced this issue Jun 12, 2017
The implementation of t he `ConstantPoolTypeIntrospector` supported:
 - Reference to a static method
 - Reference to an instance method of a particular object
 - Reference to a constructor

 But did not support:
  - Reference to an instance method of an arbitrary object of a particular type

Referencing instances methods would result in an index out of bounds exception
as  the step definition interface was expecting exactly 1 more argument then
was bound to the body. We now use this discrepancy to detect if this is an
instance method reference and include the the instance class as the first type.

Related issues:
 - #1123
 - #1126

 This fixes #1126
mpkorstanje added a commit that referenced this issue Jun 12, 2017
The implementation of t he `ConstantPoolTypeIntrospector` did not fully
support closures.

Using a closure without  scoped variables would result
in a null pointer exception.  E.g:

```java
Given("^A statement with a body expression$") { assertTrue(true) }
```

 This is resolved check if the member reference method equals the magic
 constant "INSTANCE" and return no type arguments.

Related issues:
 - #1123
 - #1126

 This fixes #1123
mpkorstanje added a commit that referenced this issue Jun 12, 2017
The implementation of t he `ConstantPoolTypeIntrospector` did not fully
support closures.

Using a closure without  scoped variables would result
in a null pointer exception.  E.g:

```java
Given("^A statement with a body expression$") { assertTrue(true) }
```

 This is resolved check if the member reference method equals the magic
 constant "INSTANCE" and return no type arguments.

Related issues:
 - #1123
 - #1126

 This fixes #1123
@donvargax
Copy link

donvargax commented Jun 14, 2017

Hi, I had the same issue and I can verify this works, I was getting

1) Error injecting constructor, cucumber.runtime.CucumberException: java.lang.ArrayIndexOutOfBoundsException: 66

But after building the support-java-8-method-references branch and updating the dependencies, everything worked OK.

PS. I tried for a couple of days with a Gradle project but I was getting this error

Warning:<i><b>root project 'cm-service-it': Unable to build Kotlin project configuration</b>
Details: java.lang.reflect.InvocationTargetException: null
Caused by: org.gradle.api.artifacts.ResolveException: Could not resolve all dependencies for configuration ':testCompileClasspath'.
Caused by: org.gradle.internal.resolve.ModuleVersionResolveException: Could not resolve io.cucumber:cucumber-kotlin-java8:2.0.0-SNAPSHOT.
Required by:
    project :
Caused by: org.gradle.internal.resolve.ModuleVersionResolveException: Could not resolve io.cucumber:cucumber-kotlin-java8:2.0.0-SNAPSHOT.
Caused by: org.gradle.api.internal.artifacts.ivyservice.ivyresolve.parser.MetaDataParseException: Could not parse POM ~/.m2/repository/io/cucumber/cucumber-kotlin-java8/2.0.0-SNAPSHOT/cucumber-kotlin-java8-2.0.0-SNAPSHOT.pom
Caused by: org.gradle.api.internal.artifacts.ivyservice.ivyresolve.parser.UnresolvedDependencyVersionException: Unable to resolve version for dependency 'io.cucumber:cucumber-java8:jar'</i>

So I got it working with maven.

mpkorstanje added a commit that referenced this issue Jun 14, 2017
The implementation of t he `ConstantPoolTypeIntrospector` did not fully
support closures.

Using a closure without  scoped variables would result
in a null pointer exception.  E.g:

```java
Given("^A statement with a body expression$") { assertTrue(true) }
```

 This is resolved check if the member reference method equals the magic
 constant "INSTANCE" and return no type arguments.

Related issues:
 - #1123
 - #1126

 This fixes #1123
@mpkorstanje
Copy link
Contributor

mpkorstanje commented Jun 14, 2017

Cheers!

PS: Owh yeah. Looks like using dependency management in a profile is a bad practice and gradle doesn't grok it. I have pushed a new commit that should fix this.

https://blog.gradle.org/maven-pom-profiles

mpkorstanje added a commit that referenced this issue Jun 14, 2017
The implementation of t he `ConstantPoolTypeIntrospector` did not fully
support closures.

Using a closure without  scoped variables would result
in a null pointer exception.  E.g:

```java
Given("^A statement with a body expression$") { assertTrue(true) }
```

 This is resolved check if the member reference method equals the magic
 constant "INSTANCE" and return no type arguments.

Related issues:
 - #1123
 - #1126

 This fixes #1123
mpkorstanje added a commit that referenced this issue Jun 14, 2017
The implementation of t he `ConstantPoolTypeIntrospector` did not fully
support closures.

Using a closure without  scoped variables would result
in a null pointer exception.  E.g:

```java
Given("^A statement with a body expression$") { assertTrue(true) }
```

 This is resolved check if the member reference method equals the magic
 constant "INSTANCE" and return no type arguments.

Related issues:
 - #1123
 - #1126

 This fixes #1123
mpkorstanje added a commit that referenced this issue Jun 14, 2017
The implementation of t he `ConstantPoolTypeIntrospector` did not fully
support closures.

Using a closure without  scoped variables would result
in a null pointer exception.  E.g:

```java
Given("^A statement with a body expression$") { assertTrue(true) }
```

 This is resolved check if the member reference method equals the magic
 constant "INSTANCE" and return no type arguments.

Related issues:
 - #1123
 - #1126

 This fixes #1123
@mpkorstanje
Copy link
Contributor

Also for future reference. cucumber-kotlin-java8 won't available as a dependency (for now). You can use cucumber-java8 directly in Kotlin.

mpkorstanje added a commit that referenced this issue Jun 14, 2017
The implementation of t he `ConstantPoolTypeIntrospector` did not fully
support closures.

Using a closure without  scoped variables would result
in a null pointer exception.  E.g:

```java
Given("^A statement with a body expression$") { assertTrue(true) }
```

 This is resolved check if the member reference method equals the magic
 constant "INSTANCE" and return no type arguments.

Related issues:
 - #1123
 - #1126

 This fixes #1123
@lock
Copy link

lock bot commented Oct 25, 2018

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot locked as resolved and limited conversation to collaborators Oct 25, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants