I have been looking for some scala fluent API for mapping object-object, similar to AutoMapper. Are there such tools in Scala?
I think there's less need of something like AutoMapper in Scala, because if you use idiomatic Scala models are easier to write and manipulate and because you can define easily automatic flattening/projection using implicit conversions.
For example here is the equivalent in Scala of AutoMapper flattening example:
// The full model
case class Order( customer: Customer, items: List[OrderLineItem]=List()) {
def addItem( product: Product, quantity: Int ) =
copy( items = OrderLineItem(product,quantity)::items )
def total = items.foldLeft(0.0){ _ + _.total }
}
case class Product( name: String, price: Double )
case class OrderLineItem( product: Product, quantity: Int ) {
def total = quantity * product.price
}
case class Customer( name: String )
case class OrderDto( customerName: String, total: Double )
// The flattening conversion
object Mappings {
implicit def order2OrderDto( order: Order ) =
OrderDto( order.customer.name, order.total )
}
//A working example
import Mappings._
val customer = Customer( "George Costanza" )
val bosco = Product( "Bosco", 4.99 )
val order = Order( customer ).addItem( bosco, 15 )
val dto: OrderDto = order // automatic conversion at compile-time !
println( dto ) // prints: OrderDto(George Costanza,74.85000000000001)
PS: I should not use Double for money amounts...
I agree with @paradigmatic, it's true that the code will be much cleaner using Scala, but sometimes you can find yourself mapping between case classes that look very similar, and that's just a waste of keystrokes.
I've started working on a project to address the issues, you can find it here: https://github.com/bfil/scala-automapper
It uses macros to generate the mappings for you.
At the moment it can map a case class to a subset of the original case class, it handles optionals, and optional fields as well as other minor things.
I'm still trying to figure out how to design the api to support renaming or mapping specific fields with custom logic, any idea or input on that would be very helpful.
It can be used for some simple cases right now, and of course if the mapping gets very complex it might just be better defining the mapping manually.
The library also allows to manually define Mapping
types between case classes in any case that can be provided as an implicit parameter to a AutoMapping.map(sourceClass)
or sourceClass.mapTo[TargetClass]
method.
UPDATE
I've just released a new version that handles Iterables, Maps and allows to pass in dynamic mappings (to support renaming and custom logic for example)
For complex mappings one may want to consider Java based mappers like
- http://modelmapper.org/user-manual/property-mapping/#conditional-mapping
- http://github.com/smooks/smooks/tree/v1.5.1/smooks-examples/model-driven-basic-virtual/
- http://orika-mapper.github.io/orika-docs/advanced-mappings.html
Scala objects can be accessed from Java:
- http://lampwww.epfl.ch/~michelou/scala/using-scala-from-java.html
- http://lampwww.epfl.ch/~michelou/android/java-to-scala.html
Implementations of implicit conversions for complex objects would be smoother with declarative mappings than handcrafted ones.
Found a longer list here:
http://www.javacodegeeks.com/2013/10/java-object-to-object-mapper.html
© 2022 - 2024 — McMap. All rights reserved.