diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cb4eb61e..7bb9bb7d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,10 +18,9 @@ jobs: matrix: os: [ ubuntu-latest ] java: - - 8.0 - - 11 - 17 - 21 + - 25 runs-on: ${{ matrix.os }} steps: @@ -40,7 +39,7 @@ jobs: uses: actions/setup-java@v5 with: java-version: ${{ matrix.java }} - distribution: 'adopt' + distribution: 'temurin' - uses: sbt/setup-sbt@v1 diff --git a/.github/workflows/version-policy-check.yml b/.github/workflows/version-policy-check.yml index ce51b1de..18fbcc29 100644 --- a/.github/workflows/version-policy-check.yml +++ b/.github/workflows/version-policy-check.yml @@ -32,7 +32,7 @@ jobs: uses: actions/setup-java@v5 with: java-version: ${{ matrix.java }} - distribution: 'adopt' + distribution: 'temurin' - uses: sbt/setup-sbt@v1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e7c23d1..1f82acee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 @@ -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) diff --git a/build.sbt b/build.sbt index 3a3e0e6f..e11393da 100644 --- a/build.sbt +++ b/build.sbt @@ -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" @@ -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: _* @@ -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) @@ -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, @@ -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) diff --git a/cucumber-scala/src/main/scala/io/cucumber/scala/Jackson3DefaultDataTableEntryTransformer.scala b/cucumber-scala/src/main/scala/io/cucumber/scala/Jackson3DefaultDataTableEntryTransformer.scala new file mode 100644 index 00000000..3b6a4b70 --- /dev/null +++ b/cucumber-scala/src/main/scala/io/cucumber/scala/Jackson3DefaultDataTableEntryTransformer.scala @@ -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 + +/**
This trait register a `DefaultDataTableEntryTransformer` using Jackson + * `ObjectMapper`.
+ * + *The `[empty]` string is used as default empty string replacement. You can + * override it if you need to.
+ * + *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.
+ * + *For Jackson 2.x, use `JacksonDefaultDataTableEntryTransformer` + * instead.
+ */ +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) + ) + } + +} diff --git a/cucumber-scala/src/main/scala/io/cucumber/scala/JacksonDefaultDataTableEntryTransformer.scala b/cucumber-scala/src/main/scala/io/cucumber/scala/JacksonDefaultDataTableEntryTransformer.scala index 22965051..c8410d05 100644 --- a/cucumber-scala/src/main/scala/io/cucumber/scala/JacksonDefaultDataTableEntryTransformer.scala +++ b/cucumber-scala/src/main/scala/io/cucumber/scala/JacksonDefaultDataTableEntryTransformer.scala @@ -10,8 +10,11 @@ import com.fasterxml.jackson.module.scala.DefaultScalaModule * override it if you need to. * *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.
+ * + *For Jackson 3.x, use `Jackson3DefaultDataTableEntryTransformer` + * instead.
*/ trait JacksonDefaultDataTableEntryTransformer extends ScalaDsl { diff --git a/docs/build.md b/docs/build.md index 434d8169..abb6ee14 100644 --- a/docs/build.md +++ b/docs/build.md @@ -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 diff --git a/docs/default_jackson_datatable_transformer.md b/docs/default_jackson_datatable_transformer.md index 6c5d59dd..f4382c8f 100644 --- a/docs/default_jackson_datatable_transformer.md +++ b/docs/default_jackson_datatable_transformer.md @@ -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