Skip to content

Add optional Jackson Default DataTable transformer #37

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 3, 2020
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ See also the [CHANGELOG](https://github.com/cucumber/cucumber-jvm/blob/master/CH
### Added

- [Doc] Users documentation on Scala DSL
- [Scala DSL] Support for transformers ([#32](https://github.com/cucumber/cucumber-jvm-scala/issues/32) Gaël Jourdan-Weil)
- See [Transformers](docs/transformers.md)
- [Transformers] Add optional `JacksonDefaultDataTableEntryTransformer` ([#31](https://github.com/cucumber/cucumber-jvm-scala/issues/31) Gaël Jourdan-Weil)
- See [here](docs/default_jackson_datatable_transformer.md)

### Changed

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ The minor version might differ because Cucumber Scala may add Scala-related feat
- [Step Definitions](docs/step_definitions.md)
- [Hooks](docs/hooks.md)
- [Transformers](docs/transformers.md)
- [Default Jackson DataTable Transformer](docs/default_jackson_datatable_transformer.md)
- [Example project](examples/README.md)
- [Reference documentation for Java](https://docs.cucumber.io/docs/cucumber/)
- [Changelog](CHANGELOG.md)
Expand Down
68 changes: 68 additions & 0 deletions docs/default_jackson_datatable_transformer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Default Jackson DataTable Transformer

Cucumber Scala provides an optional Default DataTable Transformer that uses Jackson.

It can be used to automatically convert DataTables to case classes without defining custom converters.

## Add Jackson dependency

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.10.3</version>
<scope>test</scope>
</dependency>
```

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


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

## Add the transformer

The transformer has to be added to your glue code by extending the `JacksonDefaultDataTableEntryTransformer` trait.

For instance:
```scala
class MySteps extends ScalaDsl with EN with JacksonDefaultDataTableEntryTransformer {
// Your usual glue code
}
```

### Empty string replacement

The default empty string replacement used by the default transformer is `[empty]`.

You can override it if you need to:
```scala
override def emptyStringReplacement: String = "[blank]"
```

## Example

Then, let the transformer do its work!

For instance, the following DataTable:
```gherkin
Given I have the following datatable
| field1 | field2 | field3 |
| 1.2 | true | abc |
| 2.3 | false | def |
| 3.4 | true | ghj |
```

will be automatically converted to the following case class:
```scala
case class MyCaseClass(field1: Double, field2: Boolean, field3: String)

Given("I have the following datatable") { (data: java.util.List[MyCaseClass]) =>
// Do something
}
```
4 changes: 4 additions & 0 deletions docs/transformers.md
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,8 @@ Default transformers are used when there is no specific transformer.

They can be used with object mappers like Jackson to easily convert from well known strings to objects.

See also [Default Jackson DataTable Transformer](default_jackson_datatable_transformer.md).

### String

For instance, the following definition:
Expand Down Expand Up @@ -304,6 +306,8 @@ Given("A step with a datatable") { (dataTable: DataTable) =>
}
```

This is what to `DefaultJacksonDataTableTransformer` uses.

#### Cells

For instance the following definition:
Expand Down
24 changes: 24 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,30 @@
<artifactId>cucumber-core</artifactId>
<version>${cucumber.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson-databind.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-scala_2.11</artifactId>
<version>${jackson-databind.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-scala_2.12</artifactId>
<version>${jackson-databind.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-scala_2.13</artifactId>
<version>${jackson-databind.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
Expand Down
10 changes: 5 additions & 5 deletions scala/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@
<groupId>io.cucumber</groupId>
<artifactId>cucumber-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
Expand All @@ -43,11 +48,6 @@
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
7 changes: 7 additions & 0 deletions scala/scala_2.11/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@
<scope>provided</scope>
</dependency>

<!-- Users have to provide it (for JacksonDefaultDataTableTransformer) -->
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-scala_2.11</artifactId>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
Expand Down
7 changes: 7 additions & 0 deletions scala/scala_2.12/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@
<scope>provided</scope>
</dependency>

<!-- Users have to provide it (for JacksonDefaultDataTableTransformer) -->
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-scala_2.12</artifactId>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
Expand Down
7 changes: 7 additions & 0 deletions scala/scala_2.13/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@
<scope>provided</scope>
</dependency>

<!-- Users have to provide it (for JacksonDefaultDataTableTransformer) -->
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-scala_2.13</artifactId>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package io.cucumber.scala

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule

/**
* <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:
* `com.fasterxml.jackson.module:jackson-module-scala_2.xx`
* to your project if you want to use this trait.</p>
*/
trait JacksonDefaultDataTableEntryTransformer 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 ObjectMapper with DefaultScalaModule registered.
*/
def createObjectMapper(): ObjectMapper = {
val objectMapper = new ObjectMapper()
objectMapper.registerModule(DefaultScalaModule)
}

private lazy val objectMapper: ObjectMapper = createObjectMapper()

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

}
15 changes: 15 additions & 0 deletions scala/sources/src/test/resources/tests/jackson/Jackson.feature
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 |
31 changes: 31 additions & 0 deletions scala/sources/src/test/scala/tests/jackson/JacksonSteps.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package tests.jackson

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

import scala.collection.JavaConverters._

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

class JacksonSteps extends ScalaDsl with EN with JacksonDefaultDataTableEntryTransformer {

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,8 @@
package tests.jackson

import io.cucumber.junit.{Cucumber, CucumberOptions}
import org.junit.runner.RunWith

@RunWith(classOf[Cucumber])
@CucumberOptions(strict = true)
class RunJacksonTest