Configuration
SpecBinder's code-generation behaviour is controlled through the @Gherkin2JUnitOptions annotation.
Applying configuration
@Gherkin2JUnitOptions can be placed on:
- The marker class itself — applies to that feature only.
- A shared base class — applies to every marker class that extends it. The annotation is
@Inherited, so subclasses pick the options up automatically.
@Gherkin2JUnitOptions(addSourceLineNumbers = true)
public abstract class BaseFeatureOptions {
}
@Gherkin2JUnit("specs/ShoppingCart.feature")
public abstract class ShoppingCartFeature extends BaseFeatureOptions {
}
Selective override
A child class can place its own @Gherkin2JUnitOptions to override only the options it explicitly sets. Every other option keeps the inherited value:
@Gherkin2JUnitOptions(
addSourceLineNumbers = true,
useStepKeywordInStepMethodName = true
)
public abstract class BaseFeatureOptions {
}
@Gherkin2JUnit("specs/ShoppingCart.feature")
@Gherkin2JUnitOptions(useStepKeywordInStepMethodName = false) // only this one changes
public abstract class ShoppingCartFeature extends BaseFeatureOptions {
}
In the example above, ShoppingCartFeature still inherits addSourceLineNumbers = true — only the keyword-in-method-name option is locally overridden.
Generation mode
shouldBeAbstract — boolean, default true
Controls whether the generated test class is abstract (the default) or concrete.
true(default) — generatespublic abstract class <Name>Scenarios extends <MarkerClass>. Every step method is declared asabstract. You create a concrete subclass that overrides each step. Missing implementations are compile errors.false— generatespublic class <Name>Test extends <MarkerClass>. Step methods have bodies (seeunimplementedStepBehaviorbelow). The class is immediately runnable; you implement steps by moving them into the marker class, where the generator will detect them and stop emitting stubs.
classSuffixIfAbstract — String, default "Scenarios"
The suffix used for the generated class name when shouldBeAbstract = true. For a marker ShoppingCartFeature, the default produces ShoppingCartScenarios.
classSuffixIfConcrete — String, default "Test"
The suffix used for the generated class name when shouldBeAbstract = false. For a marker ShoppingCartFeature, the default produces ShoppingCartTest.
unimplementedStepBehavior — enum, default FAIL
Only relevant when shouldBeAbstract = false. Controls the body of unimplemented step stubs in the generated concrete class:
| Value | Body |
|---|---|
FAIL (default) | Assertions.fail("Step is not yet implemented") — test fails at run time when the step is hit. |
SKIP | Assumptions.assumeTrue(false, "Step is not yet implemented") — test is reported as skipped/aborted. |
COMPILATION_ERROR | A non-Java token is emitted so the project will not compile until the step is implemented. Useful if you want concrete mode's runnable class plus abstract mode's compile-time safety. |
Empty Gherkin elements
emptyScenarioBehavior — enum, default FAIL
Behaviour for Scenario blocks that have no steps yet.
| Value | Behaviour |
|---|---|
FAIL (default) | Emits Assertions.fail("Scenario has no steps"). |
SKIP | Emits Assumptions.assumeTrue(false, ...) — reported as skipped. |
COMPILATION_ERROR | The project will not compile until the scenario has steps. |
emptyRuleBehavior — enum, default FAIL
Same three values; applies to Rule blocks that contain no scenarios.
tagForEmptyScenarios — String, default "new"
JUnit @Tag value automatically added to empty scenarios. Set to "" to disable.
tagForEmptyRules — String, default "new"
JUnit @Tag value automatically added to empty rules. Set to "" to disable.
Data tables
dataTableParameterType — enum, default LIST_OF_OBJECT_PARAMS
Controls how Gherkin data tables are represented as parameters on the generated step methods.
| Value | Generated parameter type | Notes |
|---|---|---|
LIST_OF_OBJECT_PARAMS (default) | List<XxxParam> where XxxParam is a generated record-like inner class | Strongest type safety. Column headers become typed fields with inferred types (String, Integer, Long, Double, Boolean, Character). |
LIST_OF_MAPS | List<Map<String, String>> | All values are strings; convert at the call site. |
CUCUMBER_DATA_TABLE | Cucumber's io.cucumber.datatable.DataTable | Requires getTableConverter() in the class hierarchy. Useful if you're already invested in Cucumber's data-table API. |
With LIST_OF_OBJECT_PARAMS, the generator emits a typed wrapper:
Given my cart contains the following items:
| name | qty | price | category |
| Wireless Headphones | 1 | 60.00 | electronics |
public void myCartContainsTheFollowingItems(List<ItemsParam> items) {
// your implementation
}
public static class ItemsParam {
public String name() { /* ... */ return null; }
public Integer qty() { /* ... */ return null; }
public Double price() { /* ... */ return null; }
public String category() { /* ... */ return null; }
}
You can move the ItemsParam class up into the marker class and refine its field types — for example, changing String category to an enum Category. The generator then uses your refined class and the project fails to compile if a spec row contains an unknown category. This turns spec/data drift into a compile error.
useQualifiedEnumConstants — boolean, default false
When generated code references an enum constant in a LIST_OF_OBJECT_PARAMS table, controls whether the constant is referenced as AVAILABLE (with a static import — default) or Status.AVAILABLE (qualified by enum type name). The qualified form is more verbose but reads better when several enums are in play.
Step method naming
useStepKeywordInStepMethodName — boolean, default false
Controls whether the Gherkin keyword (Given/When/Then) is included as a method-name prefix.
| Step | false (default) | true |
|---|---|---|
Given user exists | userExists() | givenUserExists() |
When user exists | userExists() | whenUserExists() |
Then user exists | userExists() | thenUserExists() |
The default collapses identical step text under different keywords into a single shared method — typically what you want.
Cucumber interop
addCucumberStepAnnotations — boolean, default false
When true, the generator adds @Given / @When / @Then annotations from io.cucumber.java.en.* on generated step methods. Useful if an IDE Cucumber/Gherkin plugin is in play and you want navigation from spec text → step method to work through those annotations.
useCucumberAnnotationsForStepMatching — boolean, default true
When true, the processor inspects Cucumber step annotations on methods in the class hierarchy to determine whether a step is already implemented — independent of method name. A method annotated with @Given("user exists") is recognised as the implementation of Given user exists even if the method itself is named setupUser.
Both regular expressions and Cucumber expressions are supported in the annotation value. Cucumber expressions support these built-in parameter types: {int}, {long}, {short}, {byte}, {float}, {double}, {bigdecimal}, {biginteger}, {word}, {string}, and the anonymous {}. Custom parameter types are not supported.
If both an annotation-matched method and a name-matched method exist for the same step, the annotation match wins.
Spec file discovery
supportedFileExtensions — String[], default {"feature", "specb"}
Extensions (without the leading dot) recognised by convention-based discovery (@Gherkin2JUnit with no value) and by glob patterns. When @Gherkin2JUnit("explicit/path.txt") provides an explicit path, the file is processed regardless of its extension.
skipGenerationForTags — String[], default {}
Regex patterns matched against tags on Feature / Rule / Scenario / Examples. When any tag on an element matches, the corresponding generated element (test class, @Nested rule, @Test method, or Examples row set) is omitted entirely — useful for excluding manual or work-in-progress specs without deleting them.
@Gherkin2JUnitOptions(skipGenerationForTags = {"manual", "wip-.*", "(?i)ignore"})
This would skip generation for elements tagged @manual, anything starting with @wip-, or @ignore (case-insensitive).
Generated code diagnostics
addSourceLineNumbers — boolean, default false
When true, the generator embeds spec file line numbers in two places:
@DisplayNameon scenarios, rules, and backgrounds — e.g.@DisplayName("Scenario [12]: Successful login").- The block comment above each step call — e.g.
/* [13] Given user exists */.
Helpful when stepping through a generated test class and you want to jump back to the corresponding spec line.
emitScenarioHash — boolean, default false
When true, each generated @Test / @ParameterizedTest method is annotated with @ScenarioHash("<sha-256-hex>") — a hash of that scenario's executable content (background steps + scenario steps, including DocStrings and DataTables). Useful for tooling that wants to detect when a scenario's meaning has changed across builds.
Build output
verbosity — enum, default NORMAL
Controls how much the annotation processor writes to the build log. Each level is cumulative — it emits everything from the levels below it.
| Level | What it emits |
|---|---|
SILENT | Errors only. No banner, no summary. |
NORMAL (default) | Errors, warnings, startup banner, end-of-round summary. |
VERBOSE | Adds per-class headers, resolved feature paths, and reasons for skipped work. |
DEBUG | Adds full stack traces, parsed Gherkin AST summaries, JavaPoet model summaries, and per-step decisions. |
The annotation-level setting overrides the global -Aspecbinder.verbosity=… annotation-processor argument.
Experimental
enableCompositeSteps — boolean, default false
Enables composite steps, where a regular step followed by one or more *-prefixed sub-steps generates a wrapper method that delegates to the sub-steps via a lambda. Inspired by JBehave's textual composites.
Given customer "Alice" has product "Laptop" in shopping cart
* login as customer $p1
* search for product $p2
* add product to cart
* verify cart contains $p2
The generator emits a wrapper that lets the implementer either provide a custom default or run the listed sub-steps as the composite's body.
Experimental — API and exact code shape may change.
Quick reference
| Option | Default |
|---|---|
shouldBeAbstract | true |
classSuffixIfAbstract | "Scenarios" |
classSuffixIfConcrete | "Test" |
unimplementedStepBehavior | FAIL |
emptyScenarioBehavior | FAIL |
emptyRuleBehavior | FAIL |
tagForEmptyScenarios | "new" |
tagForEmptyRules | "new" |
dataTableParameterType | LIST_OF_OBJECT_PARAMS |
useQualifiedEnumConstants | false |
useStepKeywordInStepMethodName | false |
addCucumberStepAnnotations | false |
useCucumberAnnotationsForStepMatching | true |
supportedFileExtensions | {"feature", "specb"} |
skipGenerationForTags | {} |
addSourceLineNumbers | false |
emitScenarioHash | false |
verbosity | NORMAL |
enableCompositeSteps | false (experimental) |