9

I am trying to set-up an example project for the Java8 dialect of Cucumber. My problem is, that I don't get it running. I always get the following hierarchy of exceptions:

Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.068 sec <<< FAILURE! - in soy.wimmer.CucumberIT
Feature: Cucumber with Java8  Time elapsed: 0.051 sec  <<< ERROR!
cucumber.runtime.CucumberException: Failed to instantiate class soy.wimmer.CucumberStepdefs
[…]
Caused by: java.lang.reflect.InvocationTargetException: null
[…]
Caused by: cucumber.runtime.CucumberException: java.lang.IllegalArgumentException: Wrong type at constant pool index
[…]
Caused by: java.lang.IllegalArgumentException: Wrong type at constant pool index
    at sun.reflect.ConstantPool.getMemberRefInfoAt0(Native Method)
    at sun.reflect.ConstantPool.getMemberRefInfoAt(ConstantPool.java:47)
    at cucumber.runtime.java8.ConstantPoolTypeIntrospector.getTypeString(ConstantPoolTypeIntrospector.java:37)
    at cucumber.runtime.java8.ConstantPoolTypeIntrospector.getGenericTypes(ConstantPoolTypeIntrospector.java:27)
    at cucumber.runtime.java.Java8StepDefinition.<init>(Java8StepDefinition.java:45)
    at cucumber.runtime.java.JavaBackend.addStepDefinition(JavaBackend.java:162)
    at cucumber.api.java8.En.Given(En.java:190)
    at soy.wimmer.CucumberStepdefs.<init>(CucumberStepdefs.java:8)
[…]

Results :

Tests in error: 
  Failed to instantiate class soy.wimmer.CucumberStepdefs

Tests run: 1, Failures: 0, Errors: 1, Skipped: 0

I have no clue why I get this error nor how to fix it.

I have packaged everything in a Maven project. The layout is like that:

./src/test/java/soy/wimmer/CucumberIT.java
./src/test/java/soy/wimmer/CucumberStepdefs.java
./src/test/resources/cucumber/cucumber-java8.feature
./pom.xml

The dependencies I include in the pom.xml are:

<dependencies>                                                               
    <dependency>                                                             
        <groupId>info.cukes</groupId>                                        
        <artifactId>cucumber-java8</artifactId>                              
        <version>1.2.3</version>                                             
        <scope>test</scope>                                                  
    </dependency>                                                            

    <dependency>                                                             
        <groupId>info.cukes</groupId>                                        
        <artifactId>cucumber-junit</artifactId>                              
        <version>1.2.3</version>                                             
        <scope>test</scope>                                                  
    </dependency>                                                            

    <dependency>                                                             
        <groupId>junit</groupId>                                             
        <artifactId>junit</artifactId>                                       
        <version>4.12</version>                                              
        <scope>test</scope>                                                  
    </dependency>                                                            
</dependencies>

Additionally the pom.xml only loads the compiler and the failsafe plugin.

My definition of CucumberIT.java:

package soy.wimmer;                                                              

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

@RunWith(Cucumber.class)                                                         
@CucumberOptions(features = "classpath:cucumber")                                
public class CucumberIT {                                                        
}        

My feature definition:

Feature: Cucumber with Java8                                                     
        As a developer                                                           
        I want to use Cucumber-java8                                             
        So that I have nicer step definitions                                    

        Scenario: Let's try it                                                   
                Given I have some dummy code                                     
                When I try to test it                                            
                Then it should work with cucumber-java8  

And this are my step definitions:

package soy.wimmer;                                                              

import cucumber.api.PendingException;                                            
import cucumber.api.java8.En;                                                    

public class CucumberStepdefs implements En {                                    
    public CucumberStepdefs() {                                                  
        Given("^I have some dummy code$", () -> {                                
            // Write code here that turns the phrase above into concrete actions 
            throw new PendingException();                                        
        });                                                                      

        When("^I try to test it$", () -> {                                       
            // Write code here that turns the phrase above into concrete actions 
            throw new PendingException();                                        
        });                                                                      

        Then("^it should work with cucumber-java(\\d+)$", (Integer arg1) -> {    
            // Write code here that turns the phrase above into concrete actions 
            throw new PendingException();                                        
        });                                                                      
    }                                                                            
}

Any idea what I'm doing wrong here?

Matthias Wimmer
  • 3,789
  • 2
  • 22
  • 41
  • Well, the exception message lacks the actual type, but I guess it’s type `18` and [this answer](http://stackoverflow.com/a/23625762/2711488) applies. In short, it seems Cucumber isn’t fit for Java 8, in fact, it’s even not 100% Java 7 compatible then… – Holger Sep 23 '15 at 08:17
  • It might be a Invokedynamic because there are lambda expressions in the constructor of the class. But I have configured the compiler to source and target version 1.8 in the pom.xml and it's the step definitions and therefore a class locally compiled, no? – Matthias Wimmer Sep 23 '15 at 09:26
  • As said in the linked answer, the issue is *not* the compiler. The problem is that there is a *runtime* tool which tries to process the compiled class file, aka bytecode. Look at the method which throws the `IllegalArgumentException`. – Holger Sep 23 '15 at 09:32
  • @Holger Okay, now I see what you mean. But it seems to be called in special java8 code as well. (I added parts of the stacktrace to my question now.) I already tried to read the code that causes the exception, but I don't get it ;-) – Matthias Wimmer Sep 23 '15 at 09:40
  • That’s an important information. With the included stacktrace, we can conclude that it’s rather likely a different issue. – Holger Sep 23 '15 at 09:44
  • 3
    We see that Cucumber is poking into Java’s private classes, i.e. `sun.reflect.ConstantPool` which is a recipe for getting compatibility problems, but it gets even worse, looking at [the offending line](https://github.com/cucumber/cucumber-jvm/blob/master/java8/src/main/java/cucumber/runtime/java8/ConstantPoolTypeIntrospector.java#L37). Big ouch. How can anyone suppose that an arbitrary location (size - 2) of the constant pool contains a particular information? That’s highly compiler dependent and even using the same compiler wouldn’t guaranty any particular order of these items. – Holger Sep 23 '15 at 09:51
  • Okay, thanks for your check. So probably I should not try to use the Java8 dialect of Cucumber (yet) and I better stick with the general Java dialect. – Matthias Wimmer Sep 23 '15 at 09:56
  • I can confirm, that it seems to be a compiler dependency of cucumber-java8. Normally I use OpenJDK. I just tried to compile/run the same tests with Sun's JDK8 and it worked immediatelly. – Matthias Wimmer Sep 23 '15 at 10:02

2 Answers2

10

The problem is caused because the Java8 dialect of Cucumber uses implementation details of Oracle's JDK8.

I was using OpenJDK8 as packaged by Debian which causes a different organisation of the constant pool. When I try the same with Oracle's JDK8 everything works as expected.

If you want to try it yourself, I published the complete example project on github: https://github.com/mawis/cucumber-java8-test

I also reported a bug at the issue tracker of cucumber-jvm here: https://github.com/cucumber/cucumber-jvm/issues/912

You might check the issue tracker to see if the problem will have been fixed in the future.

For now if you want to use cucumber-java8 it seems you have to use Oracle's implementation of the JDK.

(The fame for solving this problem belongs to Holger with his comments to the question. I just wanted to write this answer as a summary.)

Matthias Wimmer
  • 3,789
  • 2
  • 22
  • 41
  • 1
    So if I'm reading this correctly, I should see this working as long as I'm using Oracle's JDK. However, I get the exact same error as the original poster. I'm using Java version 1.8.0_60, downloaded as part of the Oracle JDK. – Jeff Nyman Sep 30 '15 at 12:41
  • 5
    It seems to also depend on the version of the JDK you are using. Recent JDKs of Oracle seem to not work as well. – Matthias Wimmer Sep 30 '15 at 12:46
7

Just use 1.2.5 version which has been recently released. It solved the bug referenced by accepted answer.

M4ks
  • 11,744
  • 7
  • 27
  • 48