tessl install tessl/maven-io-cucumber--cucumber-expressions@19.0.0Cucumber Expressions are simple patterns for matching Step Definitions with Gherkin steps
This guide will get you started with Cucumber Expressions in minutes.
Add the dependency to your pom.xml:
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-expressions</artifactId>
<version>19.0.0</version>
</dependency>For Gradle:
implementation 'io.cucumber:cucumber-expressions:19.0.0'import io.cucumber.cucumberexpressions.*;
import java.util.Locale;
import java.util.List;
import java.util.Optional;// Create parameter type registry with locale
ParameterTypeRegistry registry = new ParameterTypeRegistry(Locale.ENGLISH);
// Create expression factory
ExpressionFactory factory = new ExpressionFactory(registry);// Create expression from string
Expression expression = factory.createExpression("I have {int} cucumbers in my belly");// Match text against expression
String text = "I have 42 cucumbers in my belly";
Optional<List<Argument<?>>> match = expression.match(text);// Extract typed value
if (match.isPresent()) {
List<Argument<?>> arguments = match.get();
Integer cucumberCount = (Integer) arguments.get(0).getValue();
System.out.println("Number of cucumbers: " + cucumberCount); // 42
}import io.cucumber.cucumberexpressions.*;
import java.util.*;
public class CucumberExpressionsExample {
public static void main(String[] args) {
// Step 1: Setup
ParameterTypeRegistry registry = new ParameterTypeRegistry(Locale.ENGLISH);
ExpressionFactory factory = new ExpressionFactory(registry);
// Step 2: Create expression
Expression expr = factory.createExpression("I have {int} cucumbers in my belly");
// Step 3: Match and extract
Optional<List<Argument<?>>> match = expr.match("I have 42 cucumbers in my belly");
if (match.isPresent()) {
Integer count = (Integer) match.get().get(0).getValue();
System.out.println("Cucumber count: " + count);
} else {
System.out.println("No match found");
}
}
}// Expression with multiple parameters
Expression expr = factory.createExpression(
"User {string} has {int} items worth {float} dollars"
);
// Match text
Optional<List<Argument<?>>> match = expr.match(
"User \"John Doe\" has 5 items worth 99.99 dollars"
);
if (match.isPresent()) {
List<Argument<?>> args = match.get();
String username = (String) args.get(0).getValue();
Integer itemCount = (Integer) args.get(1).getValue();
Float totalValue = (Float) args.get(2).getValue();
System.out.println("User: " + username); // John Doe
System.out.println("Items: " + itemCount); // 5
System.out.println("Value: $" + totalValue); // $99.99
}// Simple custom type
ParameterType<Color> colorType = new ParameterType<>(
"color", // Name (used as {color} in expressions)
"red|blue|green|yellow", // Regex pattern
Color.class, // Java type
(String s) -> new Color(s) // Transformer
);registry.defineParameterType(colorType);Expression expr = factory.createExpression("I have a {color} ball");
Optional<List<Argument<?>>> match = expr.match("I have a red ball");
if (match.isPresent()) {
Color color = (Color) match.get().get(0).getValue();
System.out.println("Color: " + color); // Color.RED
}// Define enum
enum Status { ACTIVE, INACTIVE, PENDING }
// Create parameter type from enum
ParameterType<Status> statusType = ParameterType.fromEnum(Status.class);
registry.defineParameterType(statusType);
// Use in expression
Expression expr = factory.createExpression("Request is {Status}");
Optional<List<Argument<?>>> match = expr.match("Request is ACTIVE");
if (match.isPresent()) {
Status status = (Status) match.get().get(0).getValue();
System.out.println("Status: " + status); // Status.ACTIVE
}// Use parentheses for optional text
Expression expr = factory.createExpression("I have {int} cucumber(s)");
// Matches both singular and plural
expr.match("I have 1 cucumber"); // Matches
expr.match("I have 42 cucumbers"); // Matches// Use forward slash for alternatives
Expression expr = factory.createExpression("I have {int} in my belly/stomach");
expr.match("I have 42 in my belly"); // Matches
expr.match("I have 42 in my stomach"); // Matches// Expressions starting with ^ or ending with $ use regex mode
Expression regexExpr = factory.createExpression("^I have (\\d+) cucumbers$");
Optional<List<Argument<?>>> match = regexExpr.match("I have 42 cucumbers");
// The \d+ pattern is automatically converted to Integer type
if (match.isPresent()) {
Integer count = (Integer) match.get().get(0).getValue();
System.out.println("Count: " + count); // 42
}try {
// Try to use undefined parameter type
Expression expr = factory.createExpression("I have a {color} ball");
} catch (UndefinedParameterTypeException e) {
System.err.println("Parameter type not found: " + e.getUndefinedParameterTypeName());
// Register the missing type
registry.defineParameterType(colorType);
// Retry
Expression expr = factory.createExpression("I have a {color} ball");
}For better performance, cache expressions:
import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;
public class ExpressionCache {
private final ExpressionFactory factory;
private final Map<String, Expression> cache = new ConcurrentHashMap<>();
public ExpressionCache(ExpressionFactory factory) {
this.factory = factory;
}
public Expression getExpression(String expressionString) {
return cache.computeIfAbsent(expressionString, factory::createExpression);
}
}
// Usage
ExpressionCache cache = new ExpressionCache(factory);
Expression expr = cache.getExpression("I have {int} cucumbers");// Safe concurrent usage pattern
public class SafeExpressionManager {
private final ExpressionFactory factory;
public SafeExpressionManager() {
// Initialize registry and factory ONCE at startup
ParameterTypeRegistry registry = new ParameterTypeRegistry(Locale.ENGLISH);
// Register all custom types BEFORE concurrent use
registry.defineParameterType(/* custom type */);
this.factory = new ExpressionFactory(registry);
}
// Thread-safe: factory is immutable after construction
public Optional<List<Argument<?>>> matchText(String pattern, String text) {
Expression expr = factory.createExpression(pattern);
return expr.match(text);
}
}| Type | Syntax | Example Match |
|---|---|---|
int | {int} | 42, -19 |
float | {float} | 3.6, -9.2 |
double | {double} | 3.14159 |
string | {string} | "hello world" |
word | {word} | hello |
byte | {byte} | 127 |
short | {short} | 1000 |
long | {long} | 1234567890 |
biginteger | {biginteger} | 999999999999 |
bigdecimal | {bigdecimal} | 99.99 |
Problem: Expression uses {color} but type not registered.
Solution:
ParameterType<Color> colorType = new ParameterType<>(
"color", "red|blue|green", Color.class, Color::new
);
registry.defineParameterType(colorType);Problem: Extra whitespace in text breaks match.
Solution: Whitespace is significant in expressions. Ensure text matches exactly:
Expression expr = factory.createExpression("I have {int} cucumbers");
expr.match("I have 42 cucumbers"); // ✓ Matches
expr.match("I have 42 cucumbers"); // ✗ Doesn't match (extra spaces)Problem: Case mismatch breaks match.
Solution: Matches are case-sensitive by default:
Expression expr = factory.createExpression("I have {int} cucumbers");
expr.match("I have 42 cucumbers"); // ✓ Matches
expr.match("I HAVE 42 CUCUMBERS"); // ✗ Doesn't match (case mismatch)You've learned how to:
Ready to dive deeper? Check out Common Patterns or explore Real-World Scenarios.