or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

hooks.mdindex.mdstep-definitions.mdtest-context.mdtransformers.md

transformers.mddocs/

0

# Transformers

1

2

Comprehensive transformation system for converting between string representations and Java objects. Includes parameter types, data table types, doc string types, and default transformers that integrate with object mappers for automatic conversion.

3

4

## Capabilities

5

6

### Parameter Types

7

8

Custom parameter types for extracting and transforming step definition parameters from regular expressions, supporting 1-9 capture groups with full type safety.

9

10

```java { .api }

11

/**

12

* Parameter type definitions with 1-9 parameter support

13

* Converts regex capture groups to custom Java objects

14

*/

15

default <R> void ParameterType(String name, String regexp, ParameterDefinitionBody.A1<R> body) { ... }

16

default <R> void ParameterType(String name, String regexp, ParameterDefinitionBody.A2<R> body) { ... }

17

default <R> void ParameterType(String name, String regexp, ParameterDefinitionBody.A3<R> body) { ... }

18

default <R> void ParameterType(String name, String regexp, ParameterDefinitionBody.A4<R> body) { ... }

19

default <R> void ParameterType(String name, String regexp, ParameterDefinitionBody.A5<R> body) { ... }

20

default <R> void ParameterType(String name, String regexp, ParameterDefinitionBody.A6<R> body) { ... }

21

default <R> void ParameterType(String name, String regexp, ParameterDefinitionBody.A7<R> body) { ... }

22

default <R> void ParameterType(String name, String regexp, ParameterDefinitionBody.A8<R> body) { ... }

23

default <R> void ParameterType(String name, String regexp, ParameterDefinitionBody.A9<R> body) { ... }

24

```

25

26

**Usage Examples:**

27

28

```java

29

import io.cucumber.java8.En;

30

import java.math.BigDecimal;

31

import java.util.Currency;

32

import java.time.LocalDate;

33

import java.time.format.DateTimeFormatter;

34

35

public class ParameterTypeDefinitions implements En {

36

37

public ParameterTypeDefinitions() {

38

// Single parameter type - Currency amount

39

ParameterType("amount", "(\\d+\\.\\d+)\\s([A-Z]{3})", (String value, String currency) ->

40

new Amount(new BigDecimal(value), Currency.getInstance(currency)));

41

42

// Multiple parameter type - Date with format

43

ParameterType("date", "(\\d{4})-(\\d{2})-(\\d{2})", (String year, String month, String day) ->

44

LocalDate.of(Integer.parseInt(year), Integer.parseInt(month), Integer.parseInt(day)));

45

46

// Complex parameter type - Person with multiple attributes

47

ParameterType("person", "([A-Za-z]+)\\s([A-Za-z]+)\\s(\\d+)\\syears\\sold",

48

(String firstName, String lastName, String age) ->

49

new Person(firstName, lastName, Integer.parseInt(age)));

50

51

// Coordinate parameter type

52

ParameterType("coordinate", "\\(([-\\d\\.]+),\\s*([-\\d\\.]+)\\)",

53

(String x, String y) -> new Point(Double.parseDouble(x), Double.parseDouble(y)));

54

55

// Color parameter type with validation

56

ParameterType("color", "(red|green|blue|yellow|purple|orange)", (String colorName) -> {

57

switch (colorName.toLowerCase()) {

58

case "red": return Color.RED;

59

case "green": return Color.GREEN;

60

case "blue": return Color.BLUE;

61

case "yellow": return Color.YELLOW;

62

case "purple": return Color.PURPLE;

63

case "orange": return Color.ORANGE;

64

default: throw new IllegalArgumentException("Unknown color: " + colorName);

65

}

66

});

67

}

68

}

69

70

// Usage in step definitions

71

public class StepDefinitions implements En {

72

public StepDefinitions() {

73

When("I transfer {amount} to the account", (Amount amount) -> {

74

bankingService.transfer(amount);

75

});

76

77

Then("the transaction date should be {date}", (LocalDate expectedDate) -> {

78

assertEquals(expectedDate, transaction.getDate());

79

});

80

81

Given("a {person} is registered", (Person person) -> {

82

userService.register(person);

83

});

84

85

When("I click at {coordinate}", (Point coordinates) -> {

86

mouseService.click(coordinates.getX(), coordinates.getY());

87

});

88

89

Then("the button should be {color}", (Color expectedColor) -> {

90

assertEquals(expectedColor, button.getColor());

91

});

92

}

93

}

94

```

95

96

### Parameter Definition Functional Interfaces

97

98

Functional interfaces for parameter type transformation lambdas supporting 1-9 parameters.

99

100

```java { .api }

101

/**

102

* Functional interfaces for parameter type transformations

103

* Each interface corresponds to the number of regex capture groups

104

*/

105

public interface ParameterDefinitionBody {

106

@FunctionalInterface

107

interface A1<R> {

108

/**

109

* Transform single parameter to return type

110

* @param arg1 First regex capture group

111

* @return Transformed object of type R

112

* @throws Throwable Any exception during transformation

113

*/

114

R accept(String arg1) throws Throwable;

115

}

116

117

@FunctionalInterface

118

interface A2<R> {

119

/**

120

* Transform two parameters to return type

121

* @param arg1 First regex capture group

122

* @param arg2 Second regex capture group

123

* @return Transformed object of type R

124

* @throws Throwable Any exception during transformation

125

*/

126

R accept(String arg1, String arg2) throws Throwable;

127

}

128

129

@FunctionalInterface

130

interface A3<R> {

131

R accept(String arg1, String arg2, String arg3) throws Throwable;

132

}

133

134

@FunctionalInterface

135

interface A4<R> {

136

R accept(String arg1, String arg2, String arg3, String arg4) throws Throwable;

137

}

138

139

@FunctionalInterface

140

interface A5<R> {

141

R accept(String arg1, String arg2, String arg3, String arg4, String arg5) throws Throwable;

142

}

143

144

@FunctionalInterface

145

interface A6<R> {

146

R accept(String arg1, String arg2, String arg3, String arg4, String arg5, String arg6) throws Throwable;

147

}

148

149

@FunctionalInterface

150

interface A7<R> {

151

R accept(String arg1, String arg2, String arg3, String arg4, String arg5, String arg6, String arg7) throws Throwable;

152

}

153

154

@FunctionalInterface

155

interface A8<R> {

156

R accept(String arg1, String arg2, String arg3, String arg4, String arg5, String arg6, String arg7, String arg8) throws Throwable;

157

}

158

159

@FunctionalInterface

160

interface A9<R> {

161

R accept(String arg1, String arg2, String arg3, String arg4, String arg5, String arg6, String arg7, String arg8, String arg9) throws Throwable;

162

}

163

}

164

```

165

166

### Data Table Types

167

168

Transform Gherkin data tables into custom Java objects at different granularities: entire table, entry (row as Map), row (List), or individual cell.

169

170

```java { .api }

171

/**

172

* Data table type transformations for different table structures

173

*/

174

default <T> void DataTableType(DataTableDefinitionBody<T> body) { ... }

175

default <T> void DataTableType(DataTableEntryDefinitionBody<T> body) { ... }

176

default <T> void DataTableType(DataTableRowDefinitionBody<T> body) { ... }

177

default <T> void DataTableType(DataTableCellDefinitionBody<T> body) { ... }

178

179

/**

180

* Data table types with empty cell replacement

181

*/

182

default <T> void DataTableType(String replaceWithEmptyString, DataTableDefinitionBody<T> body) { ... }

183

default <T> void DataTableType(String replaceWithEmptyString, DataTableEntryDefinitionBody<T> body) { ... }

184

default <T> void DataTableType(String replaceWithEmptyString, DataTableRowDefinitionBody<T> body) { ... }

185

default <T> void DataTableType(String replaceWithEmptyString, DataTableCellDefinitionBody<T> body) { ... }

186

```

187

188

**Usage Examples:**

189

190

```java

191

public class DataTableTypeDefinitions implements En {

192

193

public DataTableTypeDefinitions() {

194

// Entry-level transformation (Map<String,String> -> Custom Object)

195

DataTableType((Map<String, String> entry) -> new User(

196

entry.get("name"),

197

entry.get("email"),

198

Integer.parseInt(entry.get("age")),

199

Boolean.parseBoolean(entry.get("active"))

200

));

201

202

// Row-level transformation (List<String> -> Custom Object)

203

DataTableType((List<String> row) -> new Product(

204

row.get(0), // name

205

new BigDecimal(row.get(1)), // price

206

Integer.parseInt(row.get(2)) // quantity

207

));

208

209

// Cell-level transformation (String -> Custom Object)

210

DataTableType((String cell) -> {

211

String[] parts = cell.split(":");

212

return new KeyValue(parts[0], parts[1]);

213

});

214

215

// Table-level transformation (entire DataTable -> Custom Object)

216

DataTableType((DataTable table) -> {

217

List<List<String>> rows = table.asLists();

218

return new Matrix(rows);

219

});

220

221

// Entry transformation with empty cell replacement

222

DataTableType("[blank]", (Map<String, String> entry) -> new Author(

223

entry.get("name"),

224

entry.get("first_publication") // "[blank]" becomes empty string

225

));

226

227

// Complex entry transformation with validation

228

DataTableType((Map<String, String> entry) -> {

229

validateRequiredFields(entry, "name", "email");

230

231

return User.builder()

232

.name(entry.get("name"))

233

.email(entry.get("email"))

234

.age(parseAge(entry.get("age")))

235

.roles(parseRoles(entry.get("roles")))

236

.createdAt(parseDate(entry.get("created_at")))

237

.build();

238

});

239

}

240

}

241

242

// Usage in step definitions

243

public class DataTableSteps implements En {

244

public DataTableSteps() {

245

Given("the following users exist:", (DataTable userTable) -> {

246

List<User> users = userTable.asList(User.class);

247

userService.createUsers(users);

248

});

249

250

When("I add these products:", (DataTable productTable) -> {

251

List<Product> products = productTable.asList(Product.class);

252

inventory.addProducts(products);

253

});

254

255

Then("the configuration should contain:", (DataTable configTable) -> {

256

List<KeyValue> config = configTable.asList(KeyValue.class);

257

assertConfigMatches(config);

258

});

259

260

// Using transposed tables

261

Given("the user details:", (DataTable userTable) -> {

262

User user = userTable.transpose().asList(User.class).get(0);

263

currentUser = user;

264

});

265

}

266

}

267

```

268

269

### Data Table Functional Interfaces

270

271

Functional interfaces for different levels of data table transformation.

272

273

```java { .api }

274

/**

275

* Transform entire data table to custom object

276

*/

277

@FunctionalInterface

278

public interface DataTableDefinitionBody<T> {

279

/**

280

* Transform complete DataTable to custom type

281

* @param table Complete data table with headers and rows

282

* @return Transformed object of type T

283

* @throws Throwable Any exception during transformation

284

*/

285

T accept(DataTable table) throws Throwable;

286

}

287

288

/**

289

* Transform data table entry (header-value map) to custom object

290

*/

291

@FunctionalInterface

292

public interface DataTableEntryDefinitionBody<T> {

293

/**

294

* Transform data table entry to custom type

295

* @param entry Map representing one table row with column headers as keys

296

* @return Transformed object of type T

297

* @throws Throwable Any exception during transformation

298

*/

299

T accept(Map<String, String> entry) throws Throwable;

300

}

301

302

/**

303

* Transform data table row (list of values) to custom object

304

*/

305

@FunctionalInterface

306

public interface DataTableRowDefinitionBody<T> {

307

/**

308

* Transform data table row to custom type

309

* @param row List of string values representing one table row

310

* @return Transformed object of type T

311

* @throws Throwable Any exception during transformation

312

*/

313

T accept(List<String> row) throws Throwable;

314

}

315

316

/**

317

* Transform individual data table cell to custom object

318

*/

319

@FunctionalInterface

320

public interface DataTableCellDefinitionBody<T> {

321

/**

322

* Transform individual cell value to custom type

323

* @param cell String value of a single table cell

324

* @return Transformed object of type T

325

* @throws Throwable Any exception during transformation

326

*/

327

T accept(String cell) throws Throwable;

328

}

329

```

330

331

### Doc String Types

332

333

Transform Gherkin doc strings (multi-line text blocks) into custom Java objects with optional content type filtering.

334

335

```java { .api }

336

/**

337

* Doc string type transformation for multi-line text content

338

*/

339

default <T> void DocStringType(String contentType, DocStringDefinitionBody<T> body) { ... }

340

```

341

342

**Usage Examples:**

343

344

```java

345

public class DocStringTypeDefinitions implements En {

346

347

public DocStringTypeDefinitions() {

348

// JSON doc string transformation

349

DocStringType("json", (String docString) -> {

350

ObjectMapper mapper = new ObjectMapper();

351

return mapper.readValue(docString, JsonNode.class);

352

});

353

354

// XML doc string transformation

355

DocStringType("xml", (String docString) -> {

356

DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();

357

return builder.parse(new ByteArrayInputStream(docString.getBytes()));

358

});

359

360

// CSV doc string transformation

361

DocStringType("csv", (String docString) -> {

362

List<List<String>> rows = new ArrayList<>();

363

String[] lines = docString.split("\\n");

364

for (String line : lines) {

365

rows.add(Arrays.asList(line.split(",")));

366

}

367

return rows;

368

});

369

370

// Custom configuration format

371

DocStringType("config", (String docString) -> {

372

Properties props = new Properties();

373

props.load(new StringReader(docString));

374

return new Configuration(props);

375

});

376

377

// SQL doc string transformation

378

DocStringType("sql", (String docString) -> {

379

return new SqlQuery(docString.trim());

380

});

381

}

382

}

383

384

// Usage in step definitions

385

public class DocStringSteps implements En {

386

public DocStringSteps() {

387

When("I send the following JSON request:", (JsonNode requestJson) -> {

388

apiClient.sendRequest(requestJson);

389

});

390

391

Then("the XML response should be:", (Document expectedXml) -> {

392

Document actualXml = apiClient.getLastXmlResponse();

393

assertXmlEquals(expectedXml, actualXml);

394

});

395

396

Given("the following CSV data:", (List<List<String>> csvData) -> {

397

dataProcessor.loadCsvData(csvData);

398

});

399

400

When("I apply this configuration:", (Configuration config) -> {

401

applicationContext.applyConfiguration(config);

402

});

403

404

Then("the database should contain:", (SqlQuery expectedQuery) -> {

405

List<Map<String, Object>> results = database.query(expectedQuery.getSql());

406

assertResultsMatch(expectedQuery, results);

407

});

408

}

409

}

410

```

411

412

### Doc String Functional Interface

413

414

```java { .api }

415

/**

416

* Transform doc string content to custom object

417

*/

418

@FunctionalInterface

419

public interface DocStringDefinitionBody<T> {

420

/**

421

* Transform doc string to custom type

422

* @param docString Multi-line string content from Gherkin doc string

423

* @return Transformed object of type T

424

* @throws Throwable Any exception during transformation

425

*/

426

T accept(String docString) throws Throwable;

427

}

428

```

429

430

### Default Transformers

431

432

Fallback transformers that handle conversions when no specific transformer is defined. Ideal for integration with object mappers like Jackson for automatic conversion.

433

434

```java { .api }

435

/**

436

* Default transformation fallbacks for parameters and data tables

437

*/

438

default void DefaultParameterTransformer(DefaultParameterTransformerBody body) { ... }

439

default void DefaultDataTableCellTransformer(DefaultDataTableCellTransformerBody body) { ... }

440

default void DefaultDataTableEntryTransformer(DefaultDataTableEntryTransformerBody body) { ... }

441

442

/**

443

* Default transformers with empty cell replacement

444

*/

445

default void DefaultDataTableCellTransformer(String replaceWithEmptyString, DefaultDataTableCellTransformerBody body) { ... }

446

default void DefaultDataTableEntryTransformer(String replaceWithEmptyString, DefaultDataTableEntryTransformerBody body) { ... }

447

```

448

449

**Usage Examples:**

450

451

```java

452

import com.fasterxml.jackson.databind.ObjectMapper;

453

import com.fasterxml.jackson.databind.JavaType;

454

455

public class DefaultTransformerDefinitions implements En {

456

private final ObjectMapper objectMapper = new ObjectMapper();

457

458

public DefaultTransformerDefinitions() {

459

// Default parameter transformer using Jackson

460

DefaultParameterTransformer((String fromValue, Type toValueType) -> {

461

JavaType javaType = objectMapper.getTypeFactory().constructType(toValueType);

462

return objectMapper.convertValue(fromValue, javaType);

463

});

464

465

// Default data table cell transformer

466

DefaultDataTableCellTransformer((String fromValue, Type toValueType) -> {

467

if (toValueType == Integer.class) {

468

return Integer.parseInt(fromValue);

469

}

470

if (toValueType == Double.class) {

471

return Double.parseDouble(fromValue);

472

}

473

if (toValueType == Boolean.class) {

474

return Boolean.parseBoolean(fromValue);

475

}

476

if (toValueType == LocalDate.class) {

477

return LocalDate.parse(fromValue);

478

}

479

return fromValue; // Fallback to string

480

});

481

482

// Default data table entry transformer using Jackson

483

DefaultDataTableEntryTransformer((Map<String, String> fromValue, Type toValueType) -> {

484

JavaType javaType = objectMapper.getTypeFactory().constructType(toValueType);

485

return objectMapper.convertValue(fromValue, javaType);

486

});

487

488

// Default transformer with empty cell replacement

489

DefaultDataTableEntryTransformer("[empty]", (Map<String, String> fromValue, Type toValueType) -> {

490

// "[empty]" in cells becomes empty string before transformation

491

JavaType javaType = objectMapper.getTypeFactory().constructType(toValueType);

492

return objectMapper.convertValue(fromValue, javaType);

493

});

494

}

495

}

496

```

497

498

### Default Transformer Functional Interfaces

499

500

```java { .api }

501

/**

502

* Default parameter transformer for unmatched parameter types

503

*/

504

@FunctionalInterface

505

public interface DefaultParameterTransformerBody {

506

/**

507

* Transform parameter value to target type when no specific transformer exists

508

* @param fromValue String value to transform

509

* @param toValueType Target Java type for transformation

510

* @return Transformed object of target type

511

* @throws Throwable Any exception during transformation

512

*/

513

Object accept(String fromValue, Type toValueType) throws Throwable;

514

}

515

516

/**

517

* Default data table cell transformer for unmatched cell types

518

*/

519

@FunctionalInterface

520

public interface DefaultDataTableCellTransformerBody {

521

/**

522

* Transform cell value to target type when no specific transformer exists

523

* @param fromValue String cell value to transform

524

* @param toValueType Target Java type for transformation

525

* @return Transformed object of target type

526

* @throws Throwable Any exception during transformation

527

*/

528

Object accept(String fromValue, Type toValueType) throws Throwable;

529

}

530

531

/**

532

* Default data table entry transformer for unmatched entry types

533

*/

534

@FunctionalInterface

535

public interface DefaultDataTableEntryTransformerBody {

536

/**

537

* Transform entry to target type when no specific transformer exists

538

* @param fromValue Map representing table row to transform

539

* @param toValueType Target Java type for transformation

540

* @return Transformed object of target type

541

* @throws Throwable Any exception during transformation

542

*/

543

Object accept(Map<String, String> fromValue, Type toValueType) throws Throwable;

544

}

545

```

546

547

### Empty Cell Handling

548

549

Data tables in Gherkin cannot represent null or empty strings unambiguously. Cucumber interprets empty cells as null, but you can configure replacement strings for empty values.

550

551

```java

552

// Configure replacement for empty cells

553

DataTableType("[blank]", (Map<String, String> entry) -> new User(

554

entry.get("name"),

555

entry.get("email") // "[blank]" becomes empty string, null stays null

556

));

557

558

// Gherkin table:

559

// | name | email |

560

// | Alice | alice@ex.com |

561

// | Bob | [blank] | <- becomes empty string

562

// | Carol | | <- becomes null

563

```