A collection of utilites used by Iterable in Scala Play! projects.
The latest version supports Play 2.8.x. To include it in your dependencies:
libraryDependencies +="com.iterable"%%"iterableplayutils"%"4.0.0"All versions can be found on maven central.
| Version | Scala version | Play! version |
|---|---|---|
| 4.0.0 | 2.13.x/2.12.x | 2.8.x |
| 3.0.0 | 2.13.x/2.12.x | 2.7.x |
| 2.0.0 | 2.12.x/2.11.x | 2.6.x |
| 1.1.1 | 2.11.x | 2.5.x |
| 1.1.0 | 2.11.x | 2.4.x |
| 1.0.1 | 2.10.x | 2.2.x |
See com.iterable.play.utils.CaseClassMapping. Uses runtime reflection to generate form mappings for case classes without all the manual typing.
Once again, this uses runtime reflection, not compile-time macros.
Suppose you have the following case class:
caseclassFoo( bar: String, baz: Option[Long] )In order to use forms/mappings, you would normally do:
valfooForm=Form( mapping( "bar"-> text, "baz"-> optional(longNumber) )(Foo.apply)(Foo.unapply) )This works fine, but it can get very cumbersome if your case classes take many parameters. It's also difficult to keep track of things if you rename the various arguments. CaseClassMapping seeks to take care of this by automatically generating a Mapping[T] for your case class T. In order to use it, any non-standard types that your case class uses must expose an implicit Mapping[T] of that type in their companion object; additionally, that mapping must be either a nullary def or a val.
For example, to create a form for our example case class Foo, you can do:
valfooForm=Form(CaseClassMapping.mapping[Foo])...and that's it!
More often we use it like this:
objectFoo{implicitvalmapping=CaseClassMapping.mapping[Foo] } // somewhere later where we need a Form[Foo]valfooForm=Form(implicitly[Mapping[Foo]])If you want to add constraints to your mapping, you can still do so; for example, if we want to make sure that Foo.bar is at least 5 characters long:
objectFoo{implicitvalmappingWithConstraint=CaseClassMapping.mapping[Foo].verifying{Constraint[Foo]("Foo.bar"){foo =>Constraints.minLength(5)(foo.bar) } } }Another use case for this is for posting form data via Play's WS. Normally, you would do something like this:
WS.url("https://some.api.expecting.form.encoded.data").post( Map( "name"->Seq("ilya"), "age"->Seq(9001.toString), "email"->Seq("ilya at iterable dot com"), "favoriteBands"->Seq("Judas Priest", "Accept") ) )That doesn't look particularly nice... so you can use UnbindableToWsRequest:
caseclassUser(name: String, age: Int, email: String, favoriteBands: Seq[String]) extendsUnbindableToWsRequest[User] objectUser{implicitvalmapping=CaseClassMapping.mapping[User] } valuser=User(name ="ilya", age =9001, email ="ilya at iterable dot com", favoriteBands =Seq("Judas Priest", "Accept")) WS.url("some url").post(user.unbindToWsRequest)Note that there is one caveat with this; Seq types. Using the previous example, the unbound data will look like this:
Map( "name"->Seq("ilya"), "age"->Seq(9001.toString), "email"->Seq("ilya at iterable dot com"), "favoriteBands[0]"->Seq("Judas Priest"), "favoriteBands[1]"->Seq("Accept") )Specifically, note that favoriteBands is unbound as
"favoriteBands[0]"->Seq("Judas Priest"), "favoriteBands[1]"->Seq("Accept")instead of
"favoriteBands"->Seq("Judas Priest", "Accept")See the tests for more sample usage.