or run

tessl search
Log in

Version

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
mavenpkg:maven/io.cucumber/cucumber-expressions@19.0.x

docs

examples

edge-cases.mdreal-world-scenarios.md
index.md
tile.json

tessl/maven-io-cucumber--cucumber-expressions

tessl install tessl/maven-io-cucumber--cucumber-expressions@19.0.0

Cucumber Expressions are simple patterns for matching Step Definitions with Gherkin steps

real-world-scenarios.mddocs/examples/

Real-World Scenarios

This document provides complete, production-ready integration examples for common use cases.

Scenario 1: BDD Test Framework Integration

Complete step definition engine for BDD testing.

import io.cucumber.cucumberexpressions.*;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class StepDefinitionEngine {
    private final ParameterTypeRegistry registry;
    private final ExpressionFactory factory;
    private final Map<Expression, Method> stepDefinitions = new ConcurrentHashMap<>();
    
    public StepDefinitionEngine(Locale locale) {
        this.registry = new ParameterTypeRegistry(locale);
        registerCustomTypes();
        this.factory = new ExpressionFactory(registry);
    }
    
    private void registerCustomTypes() {
        // Register domain-specific types
        registry.defineParameterType(new ParameterType<>(
            "user",
            "[A-Za-z][A-Za-z0-9_]*",
            String.class,
            s -> s
        ));
        
        registry.defineParameterType(new ParameterType<>(
            "email",
            "[\\w.+-]+@[\\w.-]+\\.[a-z]{2,}",
            String.class,
            s -> s
        ));
        
        // Register enums
        registry.defineParameterType(ParameterType.fromEnum(Status.class));
    }
    
    public void registerStepDefinition(String pattern, Method method) {
        Expression expr = factory.createExpression(pattern);
        stepDefinitions.put(expr, method);
    }
    
    public void executeStep(String stepText, Object testInstance) throws Exception {
        for (Map.Entry<Expression, Method> entry : stepDefinitions.entrySet()) {
            Optional<List<Argument<?>>> match = entry.getKey().match(stepText);
            if (match.isPresent()) {
                Method method = entry.getValue();
                Object[] args = extractArguments(match.get(), method);
                method.invoke(testInstance, args);
                return;
            }
        }
        throw new IllegalArgumentException("No matching step definition for: " + stepText);
    }
    
    private Object[] extractArguments(List<Argument<?>> arguments, Method method) {
        Object[] args = new Object[arguments.size()];
        for (int i = 0; i < arguments.size(); i++) {
            args[i] = arguments.get(i).getValue();
        }
        return args;
    }
}

// Usage in test class
enum Status { ACTIVE, INACTIVE, PENDING }

public class UserSteps {
    private final StepDefinitionEngine engine;
    private final Map<String, User> users = new HashMap<>();
    
    public UserSteps() {
        this.engine = new StepDefinitionEngine(Locale.ENGLISH);
        registerSteps();
    }
    
    private void registerSteps() throws NoSuchMethodException {
        engine.registerStepDefinition(
            "User {user} registers with email {email}",
            UserSteps.class.getMethod("userRegisters", String.class, String.class)
        );
        
        engine.registerStepDefinition(
            "User {user} is {Status}",
            UserSteps.class.getMethod("userHasStatus", String.class, Status.class)
        );
    }
    
    public void userRegisters(String username, String email) {
        users.put(username, new User(username, email));
        System.out.println("Registered user: " + username + " with email: " + email);
    }
    
    public void userHasStatus(String username, Status status) {
        User user = users.get(username);
        user.setStatus(status);
        System.out.println("User " + username + " status: " + status);
    }
    
    public void runTest() throws Exception {
        engine.executeStep("User john registers with email john@example.com", this);
        engine.executeStep("User john is ACTIVE", this);
    }
}

Scenario 2: REST API Validation Framework

Validate REST API requests using expressions.

import io.cucumber.cucumberexpressions.*;
import java.util.*;
import java.util.regex.Pattern;

public class ApiValidationFramework {
    private final ExpressionFactory factory;
    
    public ApiValidationFramework(ParameterTypeRegistry registry) {
        registerApiTypes(registry);
        this.factory = new ExpressionFactory(registry);
    }
    
    private void registerApiTypes(ParameterTypeRegistry registry) {
        // HTTP method
        registry.defineParameterType(new ParameterType<>(
            "method",
            "GET|POST|PUT|DELETE|PATCH",
            String.class,
            s -> s
        ));
        
        // Status code
        registry.defineParameterType(new ParameterType<>(
            "status",
            "\\d{3}",
            Integer.class,
            Integer::parseInt
        ));
        
        // JSON path
        registry.defineParameterType(new ParameterType<>(
            "jsonpath",
            "\\$[\\w.\\[\\]]+",
            String.class,
            s -> s
        ));
    }
    
    public ValidationResult validate(String rule, Map<String, Object> apiResponse) {
        List<String> errors = new ArrayList<>();
        
        try {
            Expression expr = factory.createExpression(rule);
            
            // Example: "Response status should be {status}"
            if (rule.contains("status")) {
                Optional<List<Argument<?>>> match = expr.match(rule);
                if (match.isPresent()) {
                    Integer expectedStatus = (Integer) match.get().get(0).getValue();
                    Integer actualStatus = (Integer) apiResponse.get("status");
                    
                    if (!expectedStatus.equals(actualStatus)) {
                        errors.add("Expected status " + expectedStatus + 
                                 " but got " + actualStatus);
                    }
                }
            }
            
            return new ValidationResult(errors.isEmpty(), errors);
            
        } catch (Exception e) {
            errors.add("Validation error: " + e.getMessage());
            return new ValidationResult(false, errors);
        }
    }
    
    public static class ValidationResult {
        private final boolean valid;
        private final List<String> errors;
        
        public ValidationResult(boolean valid, List<String> errors) {
            this.valid = valid;
            this.errors = errors;
        }
        
        public boolean isValid() { return valid; }
        public List<String> getErrors() { return errors; }
    }
}

// Usage
ParameterTypeRegistry registry = new ParameterTypeRegistry(Locale.ENGLISH);
ApiValidationFramework validator = new ApiValidationFramework(registry);

Map<String, Object> response = new HashMap<>();
response.put("status", 200);
response.put("body", "{\"user\":\"john\"}");

ApiValidationFramework.ValidationResult result = validator.validate(
    "Response status should be {status}",
    response
);

if (result.isValid()) {
    System.out.println("API validation passed");
} else {
    result.getErrors().forEach(System.err::println);
}

Scenario 3: Log Parser with Expressions

Parse structured logs using cucumber expressions.

import io.cucumber.cucumberexpressions.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

public class LogParser {
    private final ExpressionFactory factory;
    private final Map<String, Expression> patterns = new LinkedHashMap<>();
    
    public LogParser(ParameterTypeRegistry registry) {
        registerLogTypes(registry);
        this.factory = new ExpressionFactory(registry);
        initializePatterns();
    }
    
    private void registerLogTypes(ParameterTypeRegistry registry) {
        // Timestamp
        registry.defineParameterType(new ParameterType<>(
            "timestamp",
            "\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}",
            LocalDateTime.class,
            s -> LocalDateTime.parse(s, DateTimeFormatter.ISO_LOCAL_DATE_TIME)
        ));
        
        // Log level
        registry.defineParameterType(new ParameterType<>(
            "level",
            "DEBUG|INFO|WARN|ERROR|FATAL",
            LogLevel.class,
            LogLevel::valueOf
        ));
        
        // Thread ID
        registry.defineParameterType(new ParameterType<>(
            "thread",
            "thread-\\d+",
            String.class,
            s -> s
        ));
    }
    
    private void initializePatterns() {
        patterns.put("standard", factory.createExpression(
            "{timestamp} [{level}] ({thread}) - {string}"
        ));
        
        patterns.put("error", factory.createExpression(
            "{timestamp} [{level}] ({thread}) - Error: {string} at {word}"
        ));
    }
    
    public LogEntry parseLine(String logLine) {
        for (Map.Entry<String, Expression> entry : patterns.entrySet()) {
            Optional<List<Argument<?>>> match = entry.getValue().match(logLine);
            if (match.isPresent()) {
                return createLogEntry(entry.getKey(), match.get());
            }
        }
        return null;
    }
    
    private LogEntry createLogEntry(String pattern, List<Argument<?>> args) {
        LogEntry entry = new LogEntry();
        entry.setPattern(pattern);
        
        if (pattern.equals("standard")) {
            entry.setTimestamp((LocalDateTime) args.get(0).getValue());
            entry.setLevel((LogLevel) args.get(1).getValue());
            entry.setThread((String) args.get(2).getValue());
            entry.setMessage((String) args.get(3).getValue());
        } else if (pattern.equals("error")) {
            entry.setTimestamp((LocalDateTime) args.get(0).getValue());
            entry.setLevel((LogLevel) args.get(1).getValue());
            entry.setThread((String) args.get(2).getValue());
            entry.setError((String) args.get(3).getValue());
            entry.setLocation((String) args.get(4).getValue());
        }
        
        return entry;
    }
    
    enum LogLevel { DEBUG, INFO, WARN, ERROR, FATAL }
    
    static class LogEntry {
        private String pattern;
        private LocalDateTime timestamp;
        private LogLevel level;
        private String thread;
        private String message;
        private String error;
        private String location;
        
        // Getters and setters...
        public void setPattern(String pattern) { this.pattern = pattern; }
        public void setTimestamp(LocalDateTime timestamp) { this.timestamp = timestamp; }
        public void setLevel(LogLevel level) { this.level = level; }
        public void setThread(String thread) { this.thread = thread; }
        public void setMessage(String message) { this.message = message; }
        public void setError(String error) { this.error = error; }
        public void setLocation(String location) { this.location = location; }
        
        @Override
        public String toString() {
            return String.format("[%s] %s %s %s",
                level, timestamp, thread, message != null ? message : error);
        }
    }
}

// Usage
ParameterTypeRegistry registry = new ParameterTypeRegistry(Locale.ENGLISH);
LogParser parser = new LogParser(registry);

String logLine = "2026-01-30T14:23:45 [INFO] (thread-1) - \"Application started\"";
LogParser.LogEntry entry = parser.parseLine(logLine);

if (entry != null) {
    System.out.println("Parsed log: " + entry);
}

Scenario 4: Command Line Interface Parser

Parse CLI commands with cucumber expressions.

import io.cucumber.cucumberexpressions.*;
import java.util.*;

public class CliParser {
    private final ExpressionFactory factory;
    private final Map<String, CommandHandler> commands = new HashMap<>();
    
    public CliParser(ParameterTypeRegistry registry) {
        this.factory = new ExpressionFactory(registry);
    }
    
    public void registerCommand(String pattern, CommandHandler handler) {
        commands.put(pattern, handler);
    }
    
    public CommandResult execute(String commandLine) {
        for (Map.Entry<String, CommandHandler> entry : commands.entrySet()) {
            String pattern = entry.getKey();
            CommandHandler handler = entry.getValue();
            
            try {
                Expression expr = factory.createExpression(pattern);
                Optional<List<Argument<?>>> match = expr.match(commandLine);
                
                if (match.isPresent()) {
                    Object[] args = match.get().stream()
                        .map(Argument::getValue)
                        .toArray();
                    
                    String result = handler.execute(args);
                    return CommandResult.success(result);
                }
            } catch (Exception e) {
                return CommandResult.error(e.getMessage());
            }
        }
        
        return CommandResult.error("Unknown command: " + commandLine);
    }
    
    @FunctionalInterface
    public interface CommandHandler {
        String execute(Object[] args) throws Exception;
    }
    
    public static class CommandResult {
        private final boolean success;
        private final String output;
        
        private CommandResult(boolean success, String output) {
            this.success = success;
            this.output = output;
        }
        
        public static CommandResult success(String output) {
            return new CommandResult(true, output);
        }
        
        public static CommandResult error(String error) {
            return new CommandResult(false, error);
        }
        
        public boolean isSuccess() { return success; }
        public String getOutput() { return output; }
    }
}

// Usage
ParameterTypeRegistry registry = new ParameterTypeRegistry(Locale.ENGLISH);
CliParser cli = new CliParser(registry);

// Register commands
cli.registerCommand("list users", args -> {
    return "Users: [john, jane, bob]";
});

cli.registerCommand("create user {word} with email {word}", args -> {
    String username = (String) args[0];
    String email = (String) args[1];
    return "Created user " + username + " with email " + email;
});

cli.registerCommand("delete user {word}", args -> {
    String username = (String) args[0];
    return "Deleted user " + username;
});

// Execute commands
CliParser.CommandResult result1 = cli.execute("list users");
System.out.println(result1.getOutput());

CliParser.CommandResult result2 = cli.execute("create user alice with email alice@example.com");
System.out.println(result2.getOutput());

Scenario 5: Configuration File Parser

Parse configuration files with structured values.

import io.cucumber.cucumberexpressions.*;
import java.util.*;

public class ConfigParser {
    private final ExpressionFactory factory;
    private final Map<String, Object> config = new HashMap<>();
    
    public ConfigParser(ParameterTypeRegistry registry) {
        registerConfigTypes(registry);
        this.factory = new ExpressionFactory(registry);
    }
    
    private void registerConfigTypes(ParameterTypeRegistry registry) {
        // Boolean
        registry.defineParameterType(new ParameterType<>(
            "bool",
            "true|false|yes|no|on|off",
            Boolean.class,
            s -> s.matches("true|yes|on")
        ));
        
        // Port number
        registry.defineParameterType(new ParameterType<>(
            "port",
            "\\d{1,5}",
            Integer.class,
            s -> {
                int port = Integer.parseInt(s);
                if (port < 1 || port > 65535) {
                    throw new IllegalArgumentException("Invalid port: " + port);
                }
                return port;
            }
        ));
        
        // Path
        registry.defineParameterType(new ParameterType<>(
            "path",
            "[\\w/.-]+",
            String.class,
            s -> s
        ));
    }
    
    public void parseLine(String line) {
        // Remove comments
        int commentIndex = line.indexOf('#');
        if (commentIndex >= 0) {
            line = line.substring(0, commentIndex);
        }
        line = line.trim();
        
        if (line.isEmpty()) {
            return;
        }
        
        // Parse different config formats
        parseConfigLine(line);
    }
    
    private void parseConfigLine(String line) {
        Expression[] patterns = {
            factory.createExpression("set {word} to {int}"),
            factory.createExpression("set {word} to {bool}"),
            factory.createExpression("set {word} to {string}"),
            factory.createExpression("server port is {port}"),
            factory.createExpression("database path is {path}")
        };
        
        for (Expression expr : patterns) {
            Optional<List<Argument<?>>> match = expr.match(line);
            if (match.isPresent()) {
                storeConfig(match.get());
                return;
            }
        }
        
        throw new IllegalArgumentException("Invalid config line: " + line);
    }
    
    private void storeConfig(List<Argument<?>> args) {
        if (args.size() >= 2) {
            String key = (String) args.get(0).getValue();
            Object value = args.get(1).getValue();
            config.put(key, value);
        }
    }
    
    public Map<String, Object> getConfig() {
        return Collections.unmodifiableMap(config);
    }
}

// Usage
ParameterTypeRegistry registry = new ParameterTypeRegistry(Locale.ENGLISH);
ConfigParser parser = new ConfigParser(registry);

// Parse config lines
parser.parseLine("set timeout to 30");
parser.parseLine("set debug to true");
parser.parseLine("set name to \"MyApp\"");
parser.parseLine("server port is 8080");
parser.parseLine("database path is /var/lib/data");

// Get config
Map<String, Object> config = parser.getConfig();
config.forEach((key, value) -> 
    System.out.println(key + " = " + value + " (" + value.getClass().getSimpleName() + ")")
);

Scenario 6: Data Migration Script Parser

Parse data migration scripts with complex transformations.

import io.cucumber.cucumberexpressions.*;
import java.util.*;
import java.time.LocalDate;

public class MigrationScriptParser {
    private final ExpressionFactory factory;
    private final List<MigrationCommand> commands = new ArrayList<>();
    
    public MigrationScriptParser(ParameterTypeRegistry registry) {
        registerMigrationTypes(registry);
        this.factory = new ExpressionFactory(registry);
    }
    
    private void registerMigrationTypes(ParameterTypeRegistry registry) {
        // Table name
        registry.defineParameterType(new ParameterType<>(
            "table",
            "[a-z_][a-z0-9_]*",
            String.class,
            s -> s
        ));
        
        // Column name
        registry.defineParameterType(new ParameterType<>(
            "column",
            "[a-z_][a-z0-9_]*",
            String.class,
            s -> s
        ));
        
        // Data type
        registry.defineParameterType(new ParameterType<>(
            "datatype",
            "VARCHAR|INTEGER|DATE|BOOLEAN|TEXT",
            String.class,
            s -> s
        ));
    }
    
    public void parseScript(String script) {
        String[] lines = script.split("\\n");
        for (String line : lines) {
            line = line.trim();
            if (line.isEmpty() || line.startsWith("--")) {
                continue;
            }
            parseLine(line);
        }
    }
    
    private void parseLine(String line) {
        // CREATE TABLE
        Expression createTable = factory.createExpression(
            "CREATE TABLE {table}"
        );
        Optional<List<Argument<?>>> match1 = createTable.match(line);
        if (match1.isPresent()) {
            String tableName = (String) match1.get().get(0).getValue();
            commands.add(new CreateTableCommand(tableName));
            return;
        }
        
        // ADD COLUMN
        Expression addColumn = factory.createExpression(
            "ADD COLUMN {column} {datatype} TO {table}"
        );
        Optional<List<Argument<?>>> match2 = addColumn.match(line);
        if (match2.isPresent()) {
            String columnName = (String) match2.get().get(0).getValue();
            String dataType = (String) match2.get().get(1).getValue();
            String tableName = (String) match2.get().get(2).getValue();
            commands.add(new AddColumnCommand(tableName, columnName, dataType));
            return;
        }
        
        // DROP COLUMN
        Expression dropColumn = factory.createExpression(
            "DROP COLUMN {column} FROM {table}"
        );
        Optional<List<Argument<?>>> match3 = dropColumn.match(line);
        if (match3.isPresent()) {
            String columnName = (String) match3.get().get(0).getValue();
            String tableName = (String) match3.get().get(1).getValue();
            commands.add(new DropColumnCommand(tableName, columnName));
            return;
        }
    }
    
    public List<MigrationCommand> getCommands() {
        return Collections.unmodifiableList(commands);
    }
    
    // Command classes
    interface MigrationCommand {
        String toSql();
    }
    
    static class CreateTableCommand implements MigrationCommand {
        private final String tableName;
        CreateTableCommand(String tableName) { this.tableName = tableName; }
        public String toSql() { return "CREATE TABLE " + tableName + ";"; }
    }
    
    static class AddColumnCommand implements MigrationCommand {
        private final String tableName, columnName, dataType;
        AddColumnCommand(String tableName, String columnName, String dataType) {
            this.tableName = tableName;
            this.columnName = columnName;
            this.dataType = dataType;
        }
        public String toSql() {
            return "ALTER TABLE " + tableName + " ADD COLUMN " + columnName + " " + dataType + ";";
        }
    }
    
    static class DropColumnCommand implements MigrationCommand {
        private final String tableName, columnName;
        DropColumnCommand(String tableName, String columnName) {
            this.tableName = tableName;
            this.columnName = columnName;
        }
        public String toSql() {
            return "ALTER TABLE " + tableName + " DROP COLUMN " + columnName + ";";
        }
    }
}

// Usage
ParameterTypeRegistry registry = new ParameterTypeRegistry(Locale.ENGLISH);
MigrationScriptParser parser = new MigrationScriptParser(registry);

String script = """
    CREATE TABLE users
    ADD COLUMN email VARCHAR TO users
    ADD COLUMN age INTEGER TO users
    DROP COLUMN old_field FROM users
    """;

parser.parseScript(script);

List<MigrationScriptParser.MigrationCommand> commands = parser.getCommands();
commands.forEach(cmd -> System.out.println(cmd.toSql()));

Next Steps

  • Edge Cases - Advanced scenarios and corner cases
  • Common Patterns - Frequently used patterns
  • Reference Documentation - Detailed API documentation