Scala library for boilerplate-free data transformations.
In the daily life of a strongly-typed language's programmer sometimes it happens we need to transform an object of one type to another object which contains a number of the same or similar fields in their definitions.
case class MakeCoffee(id: Int, kind: String, addict: String) case class CoffeeMade(id: Int, kind: String, forAddict: String, at: ZonedDateTime)
Usual approach is to just rewrite fields one by one
val command = MakeCoffee(id = Random.nextInt, kind = "Espresso", addict = "Piotr") val event = CoffeeMade(id = command.id, kind = command.kind, forAddict = command.addict, at = ZonedDateTime.now)
While the example stays lean, in real-life code we usually end up with tons of such boilerplate, especially when:
- we maintain typed schema and want to migrate between multiple schema versions
- we apply practices like DDD (Domain-Driven-Design) where suggested approach is to separate model schemas of different bounded contexts
- we use code-generation tools like Protocol Buffers that generate primitive types like
String, while you'd prefer to use value objects in you domain-level code to improve type-safety and readability
Chimney provides a compact DSL with which you can define transformation rules and transform your objects with as little boilerplate as possible.
import io.scalaland.chimney.dsl._ val event = command.into[CoffeeMade] .withFieldComputed(_.at, _ => ZonedDateTime.now) .withFieldRenamed(_.addict, _.forAddict) .transform
Underneath it uses Scala macros to give you:
- type-safety at compile-time
- fast generated code, almost equivalent to hand-written version
- excellent error messages
- minimal overhead on compilation time
To include Chimney to your SBT project, add the following line to your
libraryDependencies += "io.scalaland" %% "chimney" % "0.4.1"
Library is released for Scala 2.11.x, 2.12.x and 2.13.x.
If you want to use it with Scala.js (or Scala Native), you need to replace
%%%. Due to some compiler bugs, it's recommended to use at least Scala 2.11.9 or 2.12.1.
Trying with Ammonite REPL
curl -s https://raw.githubusercontent.com/scalalandio/chimney/master/try-chimney.sh | bash Loading... Welcome to the Ammonite Repl 1.1.0 (Scala 2.12.4 Java 1.8.0_152) If you like Ammonite, please support our development at www.patreon.com/lihaoyi @ case class Foo(x: String, y: Int) defined class Foo @ case class Bar(x: String, y: Int, z: Boolean = true) defined class Bar @ Foo("abc", 10).transformInto[Bar] res2: Bar = Bar("abc", 10, true)
Chimney documentation is available at https://scalalandio.github.io/chimney
Thanks to JProfiler (Java profiler) for helping us develop the library and allowing us to use it during development.