tessl install tessl/maven-io-cucumber--cucumber-expressions@19.0.0Cucumber Expressions are simple patterns for matching Step Definitions with Gherkin steps
The library provides comprehensive exception types for handling parameter type conflicts, undefined types, duplicate registrations, and expression errors. All exceptions extend from the base CucumberExpressionException.
RuntimeException (unchecked)
└── CucumberExpressionException
├── AmbiguousParameterTypeException
├── UndefinedParameterTypeException
└── DuplicateTypeNameExceptionKey Characteristics:
getValue() is calledBase exception class for all cucumber expression errors.
package io.cucumber.cucumberexpressions;
/**
* Base exception for cucumber expression errors
* Extends RuntimeException for unchecked exception handling
* All library exceptions inherit from this class
*/
public class CucumberExpressionException extends RuntimeException {
// Package-private constructors - instantiated by library
}Usage:
import io.cucumber.cucumberexpressions.*;
try {
// Operations that may throw CucumberExpressionException
Expression expr = factory.createExpression("I have {int} cucumbers^");
// Note: This does NOT throw - anchors are literal text in Cucumber Expressions
} catch (CucumberExpressionException e) {
System.err.println("Expression error: " + e.getMessage());
// Handle cucumber expression specific errors
}
// Catch all library exceptions
try {
ParameterType<Custom> type = new ParameterType<>(
"custom", "pattern", Custom.class, Custom::new
);
registry.defineParameterType(type);
Expression expr = factory.createExpression("Test {custom}");
} catch (CucumberExpressionException e) {
// Catches: DuplicateTypeNameException, UndefinedParameterTypeException,
// AmbiguousParameterTypeException, and any other library exceptions
System.err.println("Library error: " + e.getMessage());
}Thrown when multiple parameter types match the same text pattern in a regular expression, making it impossible to determine which type to use.
package io.cucumber.cucumberexpressions;
import java.util.List;
import java.util.SortedSet;
import java.util.regex.Pattern;
/**
* Thrown when multiple parameter types match
* Provides information about conflicting types and suggestions for resolution
*/
public final class AmbiguousParameterTypeException extends CucumberExpressionException {
/**
* Get the regular expression pattern where ambiguity occurred
* @return Pattern with ambiguous matches
*/
public Pattern getRegexp();
/**
* Get the parameter type regexp that caused ambiguity
* This is the specific pattern fragment that matched multiple types
* @return String representation of parameter type regexp
*/
public String getParameterTypeRegexp();
/**
* Get the conflicting parameter types
* Sorted set of types that matched the same pattern
* Types are sorted by name for consistent ordering
* @return SortedSet of conflicting ParameterTypes
*/
public SortedSet<ParameterType<?>> getParameterTypes();
/**
* Get suggested alternative expressions
* Provides candidate expressions that avoid ambiguity by using
* Cucumber Expression syntax instead of regex
* @return List of GeneratedExpression suggestions
*/
public List<GeneratedExpression> getGeneratedExpressions();
}Usage Examples:
import io.cucumber.cucumberexpressions.*;
import java.util.Locale;
import java.util.SortedSet;
import java.util.List;
ParameterTypeRegistry registry = new ParameterTypeRegistry(Locale.ENGLISH);
// Register two parameter types with overlapping patterns
ParameterType<Currency> currencyType1 = new ParameterType<>(
"currency",
"USD|EUR|GBP",
Currency.class,
(String s) -> Currency.valueOf(s)
);
ParameterType<String> currencyType2 = new ParameterType<>(
"currencyCode",
"USD|EUR|GBP", // Same pattern!
String.class,
(String s) -> s
);
registry.defineParameterType(currencyType1);
registry.defineParameterType(currencyType2);
ExpressionFactory factory = new ExpressionFactory(registry);
try {
// This will throw because "USD" matches both types in regex mode
Expression expr = factory.createExpression("^Price in (USD|EUR|GBP)$");
} catch (AmbiguousParameterTypeException e) {
System.err.println("Ambiguous parameter types detected:");
// Get the conflicting types
SortedSet<ParameterType<?>> types = e.getParameterTypes();
for (ParameterType<?> type : types) {
System.err.println(" - " + type.getName() + " (" + type.getType() + ")");
}
// Output:
// - currency (class Currency)
// - currencyCode (class java.lang.String)
// Get the pattern that caused ambiguity
String problematicPattern = e.getParameterTypeRegexp();
System.err.println("Ambiguous pattern: " + problematicPattern);
// Output: "USD|EUR|GBP"
// Get the full regex
Pattern regex = e.getRegexp();
System.err.println("Full regex: " + regex.pattern());
// Get suggestions
List<GeneratedExpression> suggestions = e.getGeneratedExpressions();
System.err.println("Suggestions:");
for (GeneratedExpression suggestion : suggestions) {
System.err.println(" " + suggestion.getSource());
}
// Suggestions use Cucumber Expression syntax to avoid ambiguity
}Avoiding Ambiguity:
// Option 1: Use preferForRegexpMatch to indicate preference
ParameterType<Currency> currencyType = new ParameterType<>(
"currency",
"USD|EUR|GBP",
Currency.class,
(String s) -> Currency.valueOf(s),
true, // useForSnippets
true // preferForRegexpMatch = true (marks as preferred)
);
ParameterType<String> currencyCodeType = new ParameterType<>(
"currencyCode",
"USD|EUR|GBP",
String.class,
(String s) -> s,
true,
false // preferForRegexpMatch = false (not preferred)
);
registry.defineParameterType(currencyType);
registry.defineParameterType(currencyCodeType);
// Now regex will use the preferred type
Expression expr = factory.createExpression("^Price in (USD|EUR|GBP)$");
// Uses currencyType (the preferred one)
// Option 2: Use different patterns
ParameterType<Currency> currencyType2 = new ParameterType<>(
"currency",
"USD|EUR|GBP",
Currency.class,
(String s) -> Currency.valueOf(s)
);
ParameterType<String> currencyCodeType2 = new ParameterType<>(
"currencyCode",
"[A-Z]{3}", // Different pattern
String.class,
(String s) -> s
);
// Option 3: Use Cucumber Expression syntax instead of regex
// Cucumber Expressions don't have ambiguity issues
Expression expr2 = factory.createExpression("Price in {currency}");
// Cucumber Expressions handle type selection by parameter nameThrown when an expression references a parameter type that hasn't been registered.
package io.cucumber.cucumberexpressions;
/**
* Thrown when undefined parameter type referenced
* Indicates that an expression uses {typeName} but typeName
* has not been registered in the ParameterTypeRegistry
*/
public final class UndefinedParameterTypeException extends CucumberExpressionException {
/**
* Get the name of the undefined parameter type
* @return Parameter type name that was not found (without braces)
*/
public String getUndefinedParameterTypeName();
}Usage Examples:
import io.cucumber.cucumberexpressions.*;
import java.util.Locale;
ParameterTypeRegistry registry = new ParameterTypeRegistry(Locale.ENGLISH);
ExpressionFactory factory = new ExpressionFactory(registry);
try {
// Reference undefined parameter type
Expression expr = factory.createExpression("I have a {color} ball");
// Throws: UndefinedParameterTypeException
} catch (UndefinedParameterTypeException e) {
String typeName = e.getUndefinedParameterTypeName();
System.err.println("Parameter type not found: " + typeName);
// Output: "Parameter type not found: color"
// Fix: Define the missing parameter type
ParameterType<Color> colorType = new ParameterType<>(
typeName,
"red|blue|green",
Color.class,
(String s) -> new Color(s)
);
registry.defineParameterType(colorType);
// Now it works
Expression expr = factory.createExpression("I have a {color} ball");
}Prevention:
// Always define parameter types before using them
ParameterTypeRegistry registry = new ParameterTypeRegistry(Locale.ENGLISH);
// Define all custom types first
ParameterType<Color> colorType = new ParameterType<>(
"color", "red|blue|green", Color.class, (String s) -> new Color(s)
);
ParameterType<Size> sizeType = new ParameterType<>(
"size", "small|medium|large", Size.class, (String s) -> new Size(s)
);
registry.defineParameterType(colorType);
registry.defineParameterType(sizeType);
// Then create expressions
ExpressionFactory factory = new ExpressionFactory(registry);
Expression expr1 = factory.createExpression("I have a {color} ball");
Expression expr2 = factory.createExpression("The ball is {size}");
// Both work without errors
// Validation helper
public boolean isTypeDefined(ParameterTypeRegistry registry, String typeName) {
try {
ExpressionFactory factory = new ExpressionFactory(registry);
factory.createExpression("Test {" + typeName + "}");
return true;
} catch (UndefinedParameterTypeException e) {
return false;
}
}Thrown when attempting to register a parameter type with a name that's already registered.
package io.cucumber.cucumberexpressions;
/**
* Thrown when duplicate parameter type name registered
* Indicates that defineParameterType was called with a name
* that is already in the registry
*/
public class DuplicateTypeNameException extends CucumberExpressionException {
// Package-private constructor - instantiated by library
}Usage Examples:
import io.cucumber.cucumberexpressions.*;
import java.util.Locale;
ParameterTypeRegistry registry = new ParameterTypeRegistry(Locale.ENGLISH);
// Register first parameter type
ParameterType<Color> colorType1 = new ParameterType<>(
"color",
"red|blue|green",
Color.class,
(String s) -> new Color(s)
);
registry.defineParameterType(colorType1);
try {
// Try to register another type with same name
ParameterType<String> colorType2 = new ParameterType<>(
"color", // Duplicate name!
".*",
String.class,
(String s) -> s
);
registry.defineParameterType(colorType2);
// Throws: DuplicateTypeNameException
} catch (DuplicateTypeNameException e) {
System.err.println("Duplicate parameter type name: " + e.getMessage());
}Prevention:
// Use unique names for each parameter type
ParameterType<Color> colorType = new ParameterType<>(
"color",
"red|blue|green",
Color.class,
(String s) -> new Color(s)
);
ParameterType<String> colorNameType = new ParameterType<>(
"colorName", // Different name
"red|blue|green",
String.class,
(String s) -> s
);
registry.defineParameterType(colorType);
registry.defineParameterType(colorNameType);
// Or check before registering
public void registerIfNotExists(ParameterTypeRegistry registry,
ParameterType<?> parameterType) {
try {
registry.defineParameterType(parameterType);
} catch (DuplicateTypeNameException e) {
System.out.println("Type '" + parameterType.getName() +
"' already registered, skipping");
}
}
// Or maintain a set of registered types
Set<String> registeredTypes = new HashSet<>();
if (!registeredTypes.contains(typeName)) {
registry.defineParameterType(parameterType);
registeredTypes.add(typeName);
}Invalid Cucumber Expression syntax throws CucumberExpressionException:
import io.cucumber.cucumberexpressions.*;
// Note: Anchors in Cucumber Expressions are treated as literal text, not regex anchors
Expression expr1 = factory.createExpression("I have {int} cucumbers^");
// This DOES NOT throw - anchors are accepted as literal characters
// Matches: "I have 42 cucumbers^" (with literal ^ at end)
// To use regex anchors, the expression must start with ^ or end with $
// to trigger regex mode
Expression regexExpr = factory.createExpression("^I have {int} cucumbers$");
// This creates a RegularExpression with proper anchors
// Invalid parameter type name
try {
ParameterType<String> invalid = new ParameterType<>(
"{color}", // Name contains invalid characters
".*",
String.class,
(String s) -> s
);
// This may not throw immediately during construction,
// but will cause issues when registered
} catch (CucumberExpressionException e) {
System.err.println("Invalid parameter type name: " + e.getMessage());
}
// Invalid characters in parameter type names:
// {, }, (, ), /, \, whitespaceInvalid regular expression syntax throws PatternSyntaxException:
import io.cucumber.cucumberexpressions.*;
import java.util.regex.PatternSyntaxException;
try {
// Invalid regex syntax
Expression expr = factory.createExpression("^I have (\\d+ cucumbers$");
// Missing closing parenthesis - throws PatternSyntaxException
} catch (PatternSyntaxException e) {
System.err.println("Regex syntax error: " + e.getMessage());
System.err.println("At index: " + e.getIndex());
System.err.println("Description: " + e.getDescription());
System.err.println("Pattern: " + e.getPattern());
}
// Other regex syntax errors:
try {
factory.createExpression("^I have [\\d+ cucumbers$");
// Unclosed character class
} catch (PatternSyntaxException e) {
// Handle error
}
try {
factory.createExpression("^I have (?P<count>\\d+) cucumbers$");
// Named groups not supported in Java regex (use (?<count>) instead)
} catch (PatternSyntaxException e) {
// Handle error
}Exceptions thrown from transformers are preserved and re-thrown during getValue():
import io.cucumber.cucumberexpressions.*;
// Transformer with validation
Transformer<Age> ageTransformer = (String arg) -> {
if (arg == null) {
throw new IllegalArgumentException("Age cannot be null");
}
int value = Integer.parseInt(arg);
if (value < 0 || value > 150) {
throw new IllegalArgumentException("Age must be between 0 and 150");
}
return new Age(value);
};
ParameterType<Age> ageType = new ParameterType<>(
"age", "\\d+", Age.class, ageTransformer
);
registry.defineParameterType(ageType);
Expression expr = factory.createExpression("Person is {age} years old");
// Valid age
Optional<List<Argument<?>>> match1 = expr.match("Person is 25 years old");
if (match1.isPresent()) {
Age age = (Age) match1.get().get(0).getValue();
// Success
}
// Invalid age - transformer throws
Optional<List<Argument<?>>> match2 = expr.match("Person is 200 years old");
if (match2.isPresent()) {
try {
Age age = (Age) match2.get().get(0).getValue();
// getValue() throws the IllegalArgumentException from transformer
} catch (IllegalArgumentException e) {
System.err.println("Validation error: " + e.getMessage());
// Output: "Validation error: Age must be between 0 and 150"
}
}Comprehensive Error Handling:
import io.cucumber.cucumberexpressions.*;
import java.util.regex.PatternSyntaxException;
public Expression createExpressionSafely(String expressionString) {
try {
return factory.createExpression(expressionString);
} catch (UndefinedParameterTypeException e) {
System.err.println("Missing parameter type: " + e.getUndefinedParameterTypeName());
System.err.println("Please define the parameter type before using it");
throw e;
} catch (AmbiguousParameterTypeException e) {
System.err.println("Ambiguous parameter types: " + e.getParameterTypes());
System.err.println("Ambiguous pattern: " + e.getParameterTypeRegexp());
System.err.println("Suggestions:");
for (GeneratedExpression suggestion : e.getGeneratedExpressions()) {
System.err.println(" " + suggestion.getSource());
}
throw e;
} catch (PatternSyntaxException e) {
System.err.println("Invalid regex syntax: " + e.getMessage());
System.err.println("At position: " + e.getIndex());
throw e;
} catch (CucumberExpressionException e) {
System.err.println("Expression error: " + e.getMessage());
throw e;
}
}Defensive Parameter Type Registration:
public void registerParameterTypeSafely(
ParameterTypeRegistry registry,
ParameterType<?> parameterType
) {
try {
registry.defineParameterType(parameterType);
} catch (DuplicateTypeNameException e) {
System.out.println("Type '" + parameterType.getName() +
"' already registered, skipping");
} catch (CucumberExpressionException e) {
System.err.println("Failed to register parameter type: " + e.getMessage());
throw e;
}
}Validation Before Expression Creation:
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public List<String> validateExpression(String expressionString) {
List<String> errors = new ArrayList<>();
// Check for common issues
if (expressionString.contains("^") || expressionString.contains("$")) {
if (!expressionString.startsWith("^") && !expressionString.endsWith("$")) {
// Anchors in middle might be unintentional
errors.add("Anchors (^ or $) found in middle of expression. " +
"Did you mean to use regex mode? " +
"Start with ^ or end with $ to enable regex mode.");
}
}
// Check for undefined parameter types
Pattern paramPattern = Pattern.compile("\\{([^}]+)\\}");
Matcher matcher = paramPattern.matcher(expressionString);
while (matcher.find()) {
String typeName = matcher.group(1);
if (!typeName.isEmpty() && !isBuiltInType(typeName)) {
errors.add("Parameter type '" + typeName + "' may not be defined");
}
}
// Check for unmatched braces
int openBraces = 0;
for (char c : expressionString.toCharArray()) {
if (c == '{') openBraces++;
if (c == '}') openBraces--;
if (openBraces < 0) {
errors.add("Unmatched closing brace }");
break;
}
}
if (openBraces > 0) {
errors.add("Unmatched opening brace {");
}
return errors;
}
private boolean isBuiltInType(String typeName) {
return Arrays.asList(
"int", "byte", "short", "long", "float", "double",
"biginteger", "bigdecimal", "word", "string"
).contains(typeName);
}Error Recovery:
public class ExpressionManager {
private final ExpressionFactory factory;
private final Map<String, Expression> cache = new ConcurrentHashMap<>();
private final Map<String, String> errorCache = new ConcurrentHashMap<>();
public ExpressionManager(ExpressionFactory factory) {
this.factory = factory;
}
public Result<Expression> getExpression(String expressionString) {
// Check error cache
String cachedError = errorCache.get(expressionString);
if (cachedError != null) {
return Result.error(cachedError);
}
// Check success cache
Expression cached = cache.get(expressionString);
if (cached != null) {
return Result.success(cached);
}
// Try to create expression
try {
Expression expr = factory.createExpression(expressionString);
cache.put(expressionString, expr);
return Result.success(expr);
} catch (UndefinedParameterTypeException e) {
String error = "Undefined type: " + e.getUndefinedParameterTypeName();
errorCache.put(expressionString, error);
return Result.error(error);
} catch (AmbiguousParameterTypeException e) {
String error = "Ambiguous types: " + e.getParameterTypes();
errorCache.put(expressionString, error);
return Result.error(error);
} catch (Exception e) {
String error = "Invalid expression: " + e.getMessage();
errorCache.put(expressionString, error);
return Result.error(error);
}
}
public static class Result<T> {
private final T value;
private final String error;
private Result(T value, String error) {
this.value = value;
this.error = error;
}
public static <T> Result<T> success(T value) {
return new Result<>(value, null);
}
public static <T> Result<T> error(String error) {
return new Result<>(null, error);
}
public boolean isSuccess() { return value != null; }
public T getValue() { return value; }
public String getError() { return error; }
}
}Pattern 1: Exception Translator
public class ExpressionExceptionTranslator {
public String translateToUserMessage(Exception e) {
if (e instanceof UndefinedParameterTypeException) {
UndefinedParameterTypeException upe = (UndefinedParameterTypeException) e;
return String.format(
"The expression uses '{%s}' but this type is not defined. " +
"Please register a parameter type named '%s' before using it.",
upe.getUndefinedParameterTypeName(),
upe.getUndefinedParameterTypeName()
);
} else if (e instanceof AmbiguousParameterTypeException) {
AmbiguousParameterTypeException ape = (AmbiguousParameterTypeException) e;
StringBuilder sb = new StringBuilder();
sb.append("Multiple types match the same pattern:\n");
for (ParameterType<?> type : ape.getParameterTypes()) {
sb.append(" - ").append(type.getName()).append("\n");
}
sb.append("Use preferForRegexpMatch or different patterns to resolve.");
return sb.toString();
} else if (e instanceof DuplicateTypeNameException) {
return "A parameter type with this name is already registered. " +
"Use a different name or check if the type was already added.";
} else if (e instanceof PatternSyntaxException) {
PatternSyntaxException pse = (PatternSyntaxException) e;
return String.format(
"Invalid regular expression: %s at position %d",
pse.getDescription(),
pse.getIndex()
);
} else if (e instanceof CucumberExpressionException) {
return "Expression error: " + e.getMessage();
} else {
return "Unexpected error: " + e.getMessage();
}
}
}Pattern 2: Retry with Suggestions
public Expression createWithFallback(String expressionString) {
try {
return factory.createExpression(expressionString);
} catch (UndefinedParameterTypeException e) {
// Try to auto-register common types
String typeName = e.getUndefinedParameterTypeName();
if (autoRegisterType(typeName)) {
// Retry after registration
return factory.createExpression(expressionString);
}
throw e;
} catch (AmbiguousParameterTypeException e) {
// Convert to Cucumber Expression syntax
List<GeneratedExpression> suggestions = e.getGeneratedExpressions();
if (!suggestions.isEmpty()) {
String suggested = suggestions.get(0).getSource();
System.err.println("Using suggested expression: " + suggested);
return factory.createExpression(suggested);
}
throw e;
}
}
private boolean autoRegisterType(String typeName) {
// Auto-register common custom types
switch (typeName) {
case "email":
registry.defineParameterType(new ParameterType<>(
"email", "[\\w.+-]+@[\\w.-]+\\.[a-z]{2,}",
String.class, s -> s
));
return true;
case "uuid":
registry.defineParameterType(new ParameterType<>(
"uuid", "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}",
String.class, s -> s
));
return true;
default:
return false;
}
}Pattern 3: Batch Validation
public class BatchExpressionValidator {
private final ExpressionFactory factory;
public BatchExpressionValidator(ExpressionFactory factory) {
this.factory = factory;
}
public Map<String, Either<Expression, Exception>> validateExpressions(
List<String> expressionStrings
) {
Map<String, Either<Expression, Exception>> results = new LinkedHashMap<>();
for (String exprStr : expressionStrings) {
try {
Expression expr = factory.createExpression(exprStr);
results.put(exprStr, Either.left(expr));
} catch (Exception e) {
results.put(exprStr, Either.right(e));
}
}
return results;
}
public ValidationReport generateReport(
Map<String, Either<Expression, Exception>> results
) {
ValidationReport report = new ValidationReport();
for (Map.Entry<String, Either<Expression, Exception>> entry : results.entrySet()) {
String exprStr = entry.getKey();
Either<Expression, Exception> result = entry.getValue();
if (result.isLeft()) {
report.addSuccess(exprStr);
} else {
Exception e = result.getRight();
report.addFailure(exprStr, e);
}
}
return report;
}
}Testing Exception Scenarios:
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class ExceptionTest {
@Test
public void testUndefinedParameterType() {
ParameterTypeRegistry registry = new ParameterTypeRegistry(Locale.ENGLISH);
ExpressionFactory factory = new ExpressionFactory(registry);
UndefinedParameterTypeException exception = assertThrows(
UndefinedParameterTypeException.class,
() -> factory.createExpression("I have {color} ball")
);
assertEquals("color", exception.getUndefinedParameterTypeName());
}
@Test
public void testAmbiguousParameterType() {
ParameterTypeRegistry registry = new ParameterTypeRegistry(Locale.ENGLISH);
registry.defineParameterType(new ParameterType<>(
"type1", "\\d+", Integer.class, Integer::parseInt
));
registry.defineParameterType(new ParameterType<>(
"type2", "\\d+", Long.class, Long::parseLong
));
ExpressionFactory factory = new ExpressionFactory(registry);
AmbiguousParameterTypeException exception = assertThrows(
AmbiguousParameterTypeException.class,
() -> factory.createExpression("^Count: (\\d+)$")
);
assertEquals(2, exception.getParameterTypes().size());
assertEquals("\\d+", exception.getParameterTypeRegexp());
}
@Test
public void testDuplicateTypeName() {
ParameterTypeRegistry registry = new ParameterTypeRegistry(Locale.ENGLISH);
ParameterType<String> type1 = new ParameterType<>(
"color", "red|blue", String.class, s -> s
);
registry.defineParameterType(type1);
ParameterType<String> type2 = new ParameterType<>(
"color", "green|yellow", String.class, s -> s
);
assertThrows(
DuplicateTypeNameException.class,
() -> registry.defineParameterType(type2)
);
}
@Test
public void testTransformerException() {
ParameterTypeRegistry registry = new ParameterTypeRegistry(Locale.ENGLISH);
Transformer<Integer> strictPositive = (String s) -> {
int value = Integer.parseInt(s);
if (value <= 0) {
throw new IllegalArgumentException("Must be positive");
}
return value;
};
registry.defineParameterType(new ParameterType<>(
"positive", "\\d+", Integer.class, strictPositive
));
ExpressionFactory factory = new ExpressionFactory(registry);
Expression expr = factory.createExpression("Value is {positive}");
Optional<List<Argument<?>>> match = expr.match("Value is 0");
assertTrue(match.isPresent());
// getValue() throws transformer exception
assertThrows(
IllegalArgumentException.class,
() -> match.get().get(0).getValue()
);
}
}Adding Context to Exceptions:
public class ContextualExpressionFactory {
private final ExpressionFactory delegate;
private final String context;
public ContextualExpressionFactory(ExpressionFactory delegate, String context) {
this.delegate = delegate;
this.context = context;
}
public Expression createExpression(String expressionString) {
try {
return delegate.createExpression(expressionString);
} catch (UndefinedParameterTypeException e) {
throw new CucumberExpressionException(
"In context '" + context + "': " + e.getMessage(), e
);
} catch (AmbiguousParameterTypeException e) {
throw new CucumberExpressionException(
"In context '" + context + "': " + e.getMessage(), e
);
} catch (CucumberExpressionException e) {
throw new CucumberExpressionException(
"In context '" + context + "': " + e.getMessage(), e
);
}
}
}
// Usage
ContextualExpressionFactory factory = new ContextualExpressionFactory(
new ExpressionFactory(registry),
"User authentication step definitions"
);
try {
factory.createExpression("User {user} logs in");
} catch (CucumberExpressionException e) {
System.err.println(e.getMessage());
// Output: "In context 'User authentication step definitions':
// Undefined parameter type 'user'"
}