Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,9 @@ jobs:
matrix:
os: [ ubuntu-latest ]
java:
- 8.0
- 11
- 17
- 21
- 25
runs-on: ${{ matrix.os }}
steps:

Expand All @@ -40,7 +39,7 @@ jobs:
uses: actions/setup-java@v5
with:
java-version: ${{ matrix.java }}
distribution: 'adopt'
distribution: 'temurin'

- uses: sbt/setup-sbt@v1

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/version-policy-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
uses: actions/setup-java@v5
with:
java-version: ${{ matrix.java }}
distribution: 'adopt'
distribution: 'temurin'

- uses: sbt/setup-sbt@v1

Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ See also the [CHANGELOG](https://github.com/cucumber/cucumber-jvm/blob/master/CH

### Added

- [Scala] Support for Jackson 3.x with `Jackson3DefaultDataTableEntryTransformer` trait
- Jackson 2.x is still supported with `JacksonDefaultDataTableEntryTransformer` trait

### Changed

### Deprecated
Expand All @@ -24,6 +27,7 @@ See also the [CHANGELOG](https://github.com/cucumber/cucumber-jvm/blob/master/CH
### Changed

- [Core] Update `cucumber-core` dependency to [7.30.0](https://github.com/cucumber/cucumber-jvm/blob/main/CHANGELOG.md)
- Upgrade Scala versions to 2.13.17

## [8.33.0] (2025-09-22)

Expand Down
27 changes: 23 additions & 4 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ scalaVersion := scala213

val cucumberVersion = "7.30.0"
val jacksonVersion = "2.20.0"
val jackson3Version = "3.0.0"
val mockitoScalaVersion = "1.17.45"
val junit4Version = "4.13.2"

Expand Down Expand Up @@ -83,7 +84,8 @@ lazy val root = (project in file("."))
.aggregate(
cucumberScala.projectRefs ++
integrationTestsCommon.projectRefs ++
integrationTestsJackson.projectRefs ++
integrationTestsJackson2.projectRefs ++
integrationTestsJackson3.projectRefs ++
integrationTestsPicoContainer.projectRefs ++
examplesJunit4.projectRefs ++
examplesJunit5.projectRefs: _*
Expand All @@ -99,6 +101,7 @@ lazy val cucumberScala = (projectMatrix in file("cucumber-scala"))
"io.cucumber" % "cucumber-core" % cucumberVersion,
// Users have to provide it (for JacksonDefaultDataTableTransformer)
"com.fasterxml.jackson.module" %% "jackson-module-scala" % jacksonVersion % Provided,
"tools.jackson.module" %% "jackson-module-scala" % jackson3Version % Provided,
"org.junit.jupiter" % "junit-jupiter" % junitBom.key.value % Test,
("org.mockito" %% "mockito-scala" % mockitoScalaVersion % Test)
.cross(CrossVersion.for3Use2_13)
Expand Down Expand Up @@ -158,12 +161,12 @@ lazy val integrationTestsCommon =
.dependsOn(cucumberScala % Test)
.jvmPlatform(scalaVersions = Seq(scala3, scala213, scala212))

lazy val integrationTestsJackson =
(projectMatrix in file("integration-tests/jackson"))
lazy val integrationTestsJackson2 =
(projectMatrix in file("integration-tests/jackson2"))
.settings(commonSettings)
.settings(junit5SbtSupport)
.settings(
name := "integration-tests-jackson",
name := "integration-tests-jackson2",
libraryDependencies ++= Seq(
"org.junit.platform" % "junit-platform-suite" % junitBom.key.value % Test,
"io.cucumber" % "cucumber-junit-platform-engine" % cucumberVersion % Test,
Expand All @@ -174,6 +177,22 @@ lazy val integrationTestsJackson =
.dependsOn(cucumberScala % Test)
.jvmPlatform(scalaVersions = Seq(scala3, scala213, scala212))

lazy val integrationTestsJackson3 =
(projectMatrix in file("integration-tests/jackson3"))
.settings(commonSettings)
.settings(junit5SbtSupport)
.settings(
name := "integration-tests-jackson3",
libraryDependencies ++= Seq(
"org.junit.platform" % "junit-platform-suite" % junitBom.key.value % Test,
"io.cucumber" % "cucumber-junit-platform-engine" % cucumberVersion % Test,
"tools.jackson.module" %% "jackson-module-scala" % jackson3Version % Test
),
publishArtifact := false
)
.dependsOn(cucumberScala % Test)
.jvmPlatform(scalaVersions = Seq(scala3, scala213, scala212))

lazy val integrationTestsPicoContainer =
(projectMatrix in file("integration-tests/picocontainer"))
.settings(commonSettings)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package io.cucumber.scala

import tools.jackson.databind.ObjectMapper
import tools.jackson.databind.json.JsonMapper
import tools.jackson.module.scala.ScalaModule

/** <p>This trait register a `DefaultDataTableEntryTransformer` using Jackson
* `ObjectMapper`. </p>
*
* <p>The `[empty]` string is used as default empty string replacement. You can
* override it if you need to.</p>
*
* <p>Note: Jackson is not included with Cucumber Scala, you have to add the
* dependency: `tools.jackson.module:jackson-module-scala` to your project if
* you want to use this trait.</p>
*
* <p>For Jackson 2.x, use `JacksonDefaultDataTableEntryTransformer`
* instead.</p>
*/
trait Jackson3DefaultDataTableEntryTransformer extends ScalaDsl {

/** Define the string to be used as replacement for empty. Default is
* `[empty]`.
*/
def emptyStringReplacement: String = "[empty]"

/** Create the Jackson ObjectMapper to be used. Default is a simple JsonMapper
* with ScalaModule (including all builtin modules) registered.
*/
def createObjectMapper(): ObjectMapper = {
val scalaModule = ScalaModule
.builder()
.addAllBuiltinModules()
.build()
JsonMapper.builder().addModule(scalaModule).build()
}

private lazy val objectMapper: ObjectMapper = createObjectMapper()

DefaultDataTableEntryTransformer(emptyStringReplacement) {
(fromValue: Map[String, String], toValueType: java.lang.reflect.Type) =>
objectMapper.convertValue[AnyRef](
fromValue,
objectMapper.constructType(toValueType)
)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ import com.fasterxml.jackson.module.scala.DefaultScalaModule
* override it if you need to.</p>
*
* <p>Note: Jackson is not included with Cucumber Scala, you have to add the
* dependency: `com.fasterxml.jackson.module:jackson-module-scala_2.xx` to your
* dependency: `com.fasterxml.jackson.module:jackson-module-scala` to your
* project if you want to use this trait.</p>
*
* <p>For Jackson 3.x, use `Jackson3DefaultDataTableEntryTransformer`
* instead.</p>
*/
trait JacksonDefaultDataTableEntryTransformer extends ScalaDsl {

Expand Down
3 changes: 2 additions & 1 deletion docs/build.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ The project contains several subprojects:
- `cucumber-scala`: contains the codebase of the Cucumber Scala implementation
- `integration-tests`: contains integration tests projects
- `common`: general integration tests
- `jackson`: Jackson integration specific tests
- `jackson2`: Jackson 2.x integration specific tests
- `jackson3`: Jackson 3.x integration specific tests
- `picocontainer`: Picocontainer integration specific tests
- `examples`: contains a sample project

Expand Down
32 changes: 27 additions & 5 deletions docs/default_jackson_datatable_transformer.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,54 @@ It can be used to automatically convert DataTables to case classes without defin

## Add Jackson dependency

### Jackson 2.x

To use this optional transformer, you need to have Jackson Scala in your dependencies.

```xml
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-scala_2.13</artifactId>
<version>2.13.3</version>
<version>2.20.0</version>
<scope>test</scope>
</dependency>
```

Or:
```sbt
libraryDependencies += "com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.13.3" % Test
libraryDependencies += "com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.20.0" % Test
```


The current version of Cucumber Scala has been tested against Jackson Module Scala **version 2.20.0**.

### Jackson 3.x

To use this optional transformer, you need to have Jackson Scala in your dependencies.

```xml
<dependency>
<groupId>tools.jackson.module</groupId>
<artifactId>jackson-module-scala_2.13</artifactId>
<version>3.0.0</version>
<scope>test</scope>
</dependency>
```

Or:
```sbt
libraryDependencies += "tools.jackson.module" %% "jackson-module-scala" % "3.0.0" % Test
```

The current version of Cucumber Scala has been tested against Jackson Module Scala **version 3.0.0**.

## Add the transformer

The transformer has to be added to your glue code by extending the `JacksonDefaultDataTableEntryTransformer` trait.
The transformer has to be added to your glue code by extending the `JacksonDefaultDataTableEntryTransformer` (Jackson 2.x)
or `Jackson3DefaultDataTableEntryTransformer` (Jackson 3.x) trait.

For instance:
```scala
class MySteps extends ScalaDsl with EN with JacksonDefaultDataTableEntryTransformer {
class MySteps extends ScalaDsl with EN with Jackson3DefaultDataTableEntryTransformer {
// Your usual glue code
}
```
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Feature: As Cucumber Scala, I want to provide a basic DataTable transformer using Jackson

Scenario: Use the default transformer with a basic case class
Given I have the following datatable
| field1 | field2 | field3 |
| 1.2 | true | abc |
| 2.3 | false | def |
| 3.4 | true | ghj |

Scenario: Use the default transformer with a basic case class and empty values
Given I have the following datatable, with an empty value
| field1 | field2 | field3 |
| 1.2 | true | abc |
| 2.3 | false | [blank] |
| 3.4 | true | ghj |
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Workaround for https://github.com/sbt/sbt-jupiter-interface/issues/142
# See also https://github.com/cucumber/cucumber-jvm/pull/3023
cucumber.junit-platform.discovery.as-root-engine=false
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package jackson3

import io.cucumber.scala.{
EN,
Jackson3DefaultDataTableEntryTransformer,
ScalaDsl
}

import scala.jdk.CollectionConverters._

case class MyCaseClass(field1: Double, field2: Boolean, field3: String)

class Jackson3Steps
extends ScalaDsl
with EN
with Jackson3DefaultDataTableEntryTransformer {

override def emptyStringReplacement: String = "[blank]"

Given("I have the following datatable") {
(data: java.util.List[MyCaseClass]) =>
val expected = Seq(
MyCaseClass(1.2, true, "abc"),
MyCaseClass(2.3, false, "def"),
MyCaseClass(3.4, true, "ghj")
)
assert(data.asScala == expected)
}

Given("I have the following datatable, with an empty value") {
(data: java.util.List[MyCaseClass]) =>
val expected = Seq(
MyCaseClass(1.2, true, "abc"),
MyCaseClass(2.3, false, ""),
MyCaseClass(3.4, true, "ghj")
)
assert(data.asScala == expected)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package jackson3

import io.cucumber.junit.platform.engine.Constants
import org.junit.platform.suite.api.{
ConfigurationParameter,
IncludeEngines,
SelectPackages,
Suite
}

@Suite
@IncludeEngines(Array("cucumber"))
@SelectPackages(Array("jackson3"))
@ConfigurationParameter(
key = Constants.GLUE_PROPERTY_NAME,
value = "jackson3"
)
class RunJackson3Test
Loading