Cucumber-java won't use custom @ParameterType

Viewed 3336

I have a very old cucumber-java project (v. 1.2.2) that I'm trying to update to use the current version (6.10.4). For the most part it's going well, but I'm having trouble converting an old step definition which used the @Delimiter annotation to use a custom parameter type.

This was the old step definition using the delimiter:

@Then("^there are error messages: \"(.*)\"$")
public void assertAllMessages(@Delimiter("; ") List<String> messages) throws Exception {
  // ...    
}

Since @Delimiter was removed when XStream support was removed from cucumber-java, the documentation says to replace it with a custom @ParameterType. Fair enough. I wrote this one, which should be sufficient to identify a string representation of a semi-colon-separated list and convert it to a List<String>:

@ParameterType("(?:.+;)+.+")
public List<String> stringList(String raw) {
    String[] values = raw.split(";");
    return Arrays.asList(values);
}

And then I removed the @Delimiter from the step definition, but left it otherwise as-is.

However when I run my test, it fails and indicates that I should register a parameter type for List:

Caused by: java.lang.IllegalArgumentException: Can't transform 'foo; bar; baz' to java.util.List<java.lang.String>
BuiltInParameterTransformer only supports a limited number of class types
Consider using a different object mapper or register a parameter type for java.util.List<java.lang.String>
    at io.cucumber.cucumberexpressions.BuiltInParameterTransformer.createIllegalArgumentException(BuiltInParameterTransformer.java:114)
    at io.cucumber.cucumberexpressions.BuiltInParameterTransformer.doTransform(BuiltInParameterTransformer.java:33)
    at io.cucumber.cucumberexpressions.BuiltInParameterTransformer.transform(BuiltInParameterTransformer.java:22)
    at io.cucumber.cucumberexpressions.RegularExpression.lambda$match$0(RegularExpression.java:66)
    at io.cucumber.cucumberexpressions.ParameterType$TransformerAdaptor.transform(ParameterType.java:268)
    at io.cucumber.cucumberexpressions.ParameterType.transform(ParameterType.java:233)
    ... 47 more

I know that it has successfully picked up my custom parameter type, because it's in the same file as the step definition. (Further if I create another copy elsewhere in the glue directory, it complains there's already a parameter type named "stringList" registered.)

I also tried changing the regex to just @ParameterType(".*"), but it made no difference.

How do I get Cucumber to use my custom parameter type for converting a string into a List<String>?


  • Junit 5.8.1 (with vintage engine for 4 support)
  • Cucumber-java and cucumber-junit 6.10.4
  • OpenJDK 17
2 Answers

Parameter types are part of cucumber-expressions. So instead of writing a regex you should either use a cucumber-expression or use the exact regex from the parameter type in your regular expression.

@ParameterType("(?:.+;)+.+")
public List<String> stringList(String raw) {
    String[] values = raw.split(";");
    return Arrays.asList(values);
}


@Then("there are error messages: \"{stringList}\"")
public void assertAllMessages(@Delimiter("; ") List<String> messages) throws Exception {
  // ...    
}

Assume you have this feature file:

Feature: test

  Scenario: test scenario
    Given: This string: foo; bar; baz

So, to have a proper use of custom parameter types you have to assure two things:

  1. Poprer step definition. Your step definition has to be defined as a Cucumber Expression (not regular expression).
@Given("This string: {list}")
public void givenThisString(List<String> myList){
    System.out.println(myList);
}
  1. Proper parameter type. A parameter type defined within some glued class:
@ParameterType("([^;]+);?")
public List<String> list(String[] vals){
    return Arrays.asList(vals);
}

Put your attention at that in your step definition you refer to parameter type as {list} so that Cucumber knows where to take a parser. If you do not specify type name explicitly through annotation value, Cucumber takes the type name as the name of a method you have annotated with @ParameterType

Related