In my play app, I have some action filter that does some auth stuff. It has a WrappedRequest type which includes some information after the auth has been done e.g.
case class User(f : Foo) extends extends WrappedRequest[A](request)
I have a lot of twirl templates where I want to pass this Foo in. The way I am doing it now is to create an implicit value inside each controller method which loads a template, so e.g.
def doStuff : Action{
implicit request =>
implicit val value = request.f
Ok(some_template())
}
In the template I have
// some imports
#()(implicit f : Foo)
Because I have a shed load of templates, I will have to declare the implicit in my controller method and then update each template to have that implicit picked up. Is there a better way to do this?
Related
My Scala level is a beginner and I saw an action method clearly demonstrating a declaration implicit request=>. And my question is under what types of situation should we declare clearly? I also have seen methods which don't declare implicit request=> or request=>.
Could anyone explain the advantage?
I will not cover the meaning of implicit in scala itself as it has already been answered on stackoverflow here. The play documentation also explains the use of request => here but does not give examples of a useful implicit request.
TL; DR : when in doubt, use implicit request as it may be needed by some components.
Action without request
If the request does not change the result your block of code will return, it can be omitted and you can write.
def myAction = Action { Ok("Hello World") }
With Request
If on the other hand you need to use the content of the request (header or body), then you have to add a request parameter. A common example of this is parsing the body of the request :
Action(parse.json) { request => // it works without implicit
request.body.validate[MyClass].fold(/* do something */)
}
With implicit request
The play documentation encourages us to mark the request parameter as implicit because even if you do not use the request directly, one component you use may need it as an implicit. If you ever get a missing implicit error in one of your action, it probably boils down to the fact that you forgot to make your request implicit.
I think a good example you might encounter in play is the internationalization API. To sum up, it allows to automatically inject localized messages in your templates depending on the Accept-Language header in the request. All you have to do is add the I18nSupport trait to your controller and inject a messagesApi: MessagesApi parameter (and obviously define your internationalized messages). Then, in your twirl template, you can use the localized messages. For instance :
Template :
#()(implicit messages: Messages)
#*
message will be in english, spanish, klingon... depending on the supported
languages and request Accept-Language header
*#
#messages("say-hello")
Controller :
class MyController #Inject() (val messageApi: MessageApi) extends Controller with I18nSupport {
def myAction = Action {implicit request =>
// We do not have to bother about how messages are injected
// The I18nSupport trait does the work for us
Ok(html.myTemplate())
}
}
To be able to do this, the I18nSupport trait contains a def :
implicit def request2Messages(implicit request: RequestHeader): Messages = /* ... */
It allows to get an instance of Messages automatically (the compiler will implicitly call request2Messages(yourRequest) when needed but you need to have an implicit request (or request header) in scope.
Another example I have seen is automatically getting a user instance in the scope of the action when using some security frameworks in play.
Side note
A annoying gotcha with this kind of implicit chain is that if you forget to make your request implicit, the compiler will probably complain about a missing implicit Messages in scope while the real problem is a missing implicit request.
implicit in Scala has many use cases - one of them being passing parameters implicitly to functions that define implicit parameters.
For example:
def withImplicitParameter(greeting: String)(implicit name: String): Unit = {
println(greeting + " " + name)
}
// Using implicits
implicit val name = "Bob"
withImplicitParameter("Hello") // "Bob" is passed in implicitly for name parameter. Prints "Hello Bob"
withImplicitParameter("Bye")("Joe") // "Joe" is passed in explicitly for name parameter. Prints "Bye Joe"
Therefore unless one of the functions you're calling has an implicit parameter of the type Request you don't need { implicit request => ... }
More info can be found in Scala's official documentation on implicit parameters
Another example with similar API to play's implicit req => ...
case class ClassName(name: String)
def log(msg: String)(implicit className: ClassName) =
System.out.println(s"message=`$msg` className=`${className.name}`")
val cls = Option(ClassName("ImplicitClass"))
cls.foreach { implicit name =>
log("explicit message")
}
Produces
message=`explicit message` className=`ImplicitClass`
I have a case class
case class Oauth2Request[A](
foo: String,
request: Request[A]
) extends WrappedRequest[A](request) {
def bar = foo
}
(That's play.api.mvc.WrappedRequest) Later instantiated with
val wrappedRequest = Oauth2Request("foo",otherRequest)
val publicApiRequest = wrappedRequest.copy(request=apiRequest)
comes out like this in my ide
The end result looks like with compile error
not found: value request
Why does the copy method bring up arguments that look like the constructor to WrappedRequest instead of the copy method I am expecting which can be used to copy/alter 1 or more fields of the original object?
As you can see in the docs WrappedRequest is not a case class. But it does have a copy method, as your IDE shown you, but none of these arguments are named request.
Since the constructor of the class takes one argument of type Request, why not just new WrappedRequest(apiRequest)?
Abstract problem: Create a trait that can be mixed into the companion object of a class, to give that object a method that returns an object of that class.
Concrete problem: I'm trying to create a bunch of classes for use with RESTful service calls, that know how to serialize and de-serialize themselves, like so:
case class Foo
(
var bar : String,
var blip : String
)
extends SerializeToJson
object Foo extends DeserializeFromJson
The intended usage is like so:
var f = Foo( "abc","123" )
var json = f.json
var newF = Foo.fromJson( json )
I'm using Genson to do the serialization/deserialization, which I access through a global object:
object JSON {
val parser = new ScalaGenson( new GensonBuilder() <...> )
}
Then I define the traits like so:
trait SerializeToJson {
def json : String = JSON.parser.toJson(this)
}
trait DeserializeFromJson[T <: DeserializeFromJson[T]] {
def fromJson( json : String ) : T = JSON.parser.fromJson( json )
}
This compiles. But this does not:
object Foo extends DeserializeFromJson[Foo]
I get the following error message:
type arguments [Foo] do not conform to trait DeserializeFromJson's
type parameter bounds [T <: DeserializeFromJson[T]]
I've tried creating a single trait, like so:
trait JsonSerialization[T <: JsonSerialization[T]] {
def json(implicit m: Manifest[JsonSerialization[T]]) : String =
JSON.parser.toJson(this)(m)
def fromJson( json : String ) : T =
JSON.parser.fromJson(json)
}
Now, if I just declare case class Foo (...) extends JsonSerialization[Foo] then I can't call Foo.fromJson because only an instance of class Foo has that method, not the companion object.
If I declare object Foo extend JsonSerialization[Foo] then I can compile and Foo has a .fromJson method. But at run time, the call to fromJson thinks that T is a JsonSerialization, and not a Foo, or so the following run-time error suggests:
java.lang.ClassCastException: scala.collection.immutable.HashMap$HashTrieMap cannot be cast to ...JsonSerialization
at ...JsonSerialization$class.fromJson(DataModel.scala:14)
at ...Foo.fromJson(Foo.scala:6)
And I can't declare object Foo extends Foo because I get
module extending its companion class cannot use default constructor arguments
So I can try adding constructor parameters, and that compiles and runs, but again the run-time type when it tries to deserialize is wrong, giving me the above error.
The only thing I've been able to do that works is to define fromJson in every companion object. But there MUST be a way to define it in a trait, and just mix in that trait. Right?
The solution is to simplify the type parameter for the trait.
trait DeserializeFromJson[T] {
def fromJson( json : String )(implicit m : Manifest[T]) : T =
JSON.parser.fromJson[T](json)(m)
}
Now, the companion object can extend DeserializeFromJson[Foo] and when I call Foo.fromJson( json ) it is able to tell Genson the correct type information so that an object of the appropriate type is created.
The problem is related to how implicits work.
Genson expects a Manifest that it will use to know to what type it must deserialize. This manifest is defined as implicit in Genson, meaning that it will try to get it from implicitly available manifests in the "caller code". However in your original version there is no Manifest[T] in DeserializeFromJson.
An alternate way would be to define the DeserializeFromJson like that (which will just produce a constructor with an implicit Manifest[T] argument):
abstract class DeserializeFromJson[T: Manifest] {
def fromJson( json : String ) : T = JSON.parser.fromJson[T](json)
}
object Foo extends DeserializeFromJson[Foo]
More generally if you don't bring more value by encapsulating a lib (in this case Genson), I think you shouldn't do that. As you basically reduce the features of Genson (now people can only work with strings) and introduce problems like the one you hit.
I think your type parameter constraint were originally wrong;
you had
trait DeserializeFromJson[T <: DeserializeFromJson[T]]
With your own answer, you fully relaxed it; you needed
trait DeserializeFromJson[T <: SerializeToJson]
...which the error was trying to tell you.
The need for the implicit Manifest (ClassTag now I believe) or context-bounds was on the money.
Would be nice for Scala to allow the specification of inheritance and type-parameter constraints based on class/trait and companion object relationship, given it is already aware, to some degree, when it comes to access-modifiers and implicit scopes.
My application code uses AService
trait AService {
def registerNewUser (username: String)(implicit tenant: Tenant): Future[Response]
}
to register a new user. Class Tenant is a simple case class:
case class Tenant(val vstNumber:String, val divisionNumber:String)
Trait AServiceMock mimics the registration logic by using a mocked version of AService
trait AServiceMock {
def registrationService = {
val service = mock[AService]
service.registerNewUser(anyString) returns Future(fixedResponse)
service
}
}
Iow whenever registerNewUser is called on AService the response will be "fixedResponse" (defined elsewhere).
My question is, how do I define the implicit tenant-parameter as a mockito matcher like anyString?
btw. I'm using Mockito with Specs2 (and Play2)
Sometimes you have to post on SO first to come up with the completely obvious answer (duhh):
service.registerNewUser(anyString)(any[Tenant]) returns Future(fixedResponse)
This a complement to #simou answer. For now I think this is how it should be done, but I think it is intresting to know why the alternative solution proposed by #Enrik should be avoided as it may fail at run time with a cryptic error in some circumstances.
What you can safely do is if you want an exact match on your implicit argument for your stub, you can just add it in the scope :
trait AServiceMock {
implicit val expectedTenant: Tenant = Tenant("some expected parameter")
def registrationService = {
val service = mock[AService]
service.registerNewUser(anyString) returns Future(fixedResponse)
service
}
}
This will work fine but only if service.registerNewUser is expected to be called with the exact same tenant that the one provided by the implicit value expectedTenant .
What will not reliably work on the other hand is anything in the style :
implicit val expectedTenant1: Tenant = any[Tenant]
implicit def expectedTenant2: Tenant = any[Tenant]
implicit def expectedTenant3: Tenant = eqTo(someTenant)
To reason is related to how mockito create its argument matcher.
When you write myFunction(*,12) returns "abc" mockito actually use a macro that :
add code to intialize a list were argument matcher can register
If needed, wrap all argument that are not matcher in matchers.
add code to retrive the list of matchers that were declared for this function.
In the case of expectedTenant2 or expectedTenant3 what may append is that a first argument matcher will be registerd when the function is evaludated. But the macro will not see this function is registering a macther. It will only consider the declared return type of this function and so may decide to wrap this returned value inside a second matcher.
So in practice if you have code like this
trait AServiceMock {
implicit def expectedTenant(): Tenant = any[Tenant]
def registrationService = {
val service = mock[AService]
service.registerNewUser(anyString) returns Future(fixedResponse)
service
}
}
You expect it to be like that after applying the implicit :
trait AServiceMock {
def registrationService = {
val service = mock[AService]
service.registerNewUser(anyString)(any[Tenant]) returns Future(fixedResponse)
service
}
}
But actually mockito macro will make it as something more or less like that :
trait AServiceMock {
def registrationService = {
val service = mock[AService]
// In practice the macro use DefaultMatcher and not eqTo but that do not change much for the matter we discuss.
service.registerNewUser(anyString)(eqTo(any[Tenant])) returns Future(fixedResponse)
service
}
}
So now you declare two matcher inside the implicit argument of your stub. When mockito will retrive the list of matchers that were declared for registerNewUser, it will see three of them and will think that you are trying to register a stub with three argument for a function that need only two and will log :
Invalid use of argument matchers!
2 matchers expected, 3 recorded:
I'm not yet sure why it may still work in some cases, my hypotheses are :
Maybe the macro sometime decide in some case that a matcher is not needed, and do not wrap the value returned by implicit function in an additional matcher.
Maybe with some leniency option enabled, mockito ignore additional matcher. Even if that was the case, the additonal matcher may mess up the order of the argument for your stub.
It may be also possible that under some circonstance, the scala compiler inline the implicit def, this would allow the macro to see that a matcher was used.
Background
I am trying to understand best practices for bringing implicit objects into scope within a Scala application.
I have a Playframework 2.2.0 (Scala 2.10) web app that mixes in a trait for Authorization. It checks. The Authenticated object checks that there is a user_id in scope, attempts to retrieve the user info, access token, and a data package object called a MagicNotebook from cache, database, and web service call. If the request is valid, then various objects are added to the wrapped request.
object Authenticated extends ActionBuilder[AuthenticatedRequest] {
def invokeBlock[A](request: Request[A],
block: (AuthenticatedRequest[A] => Future[SimpleResult])) = {
request.session.get(userName).map { implicit userId =>
Cache.getAs[DbUser](userKey).map { user =>
Cache.getAs[String](accessTokenKey).map { accessToken =>
Cache.getAs[MagicNotebook](magicNotebookKey(userId)).map { notebook =>
block(AuthenticatedRequest(user, accessToken, notebook, request) )
}.getOrElse(startOver)
}.getOrElse {
requestNewAccessToken(user.token).flatMap { response =>
persistAccessToken(response).map { accessToken =>
Cache.getAs[MagicNotebook](magicNotebookKey(userId)).map { notebook =>
block(AuthenticatedRequest(user, accessToken, notebook, request))
}.getOrElse(startOver)
}.getOrElse(startOver)
}
}
}.getOrElse(startOver) // user not found in Cache
}.getOrElse(startOver) // userName not found in session
}
}
}
case class AuthenticatedRequest[A](user: DbUser,
accessToken: String,
magic: MagicNotebook,
request: Request[A])
extends WrappedRequest[A](request)
Question
What is the best way to bring these implicit variables into scope?
Through an implicit class?
I tried to use an implicit companion class, with the following code:
object Helper {
implicit class Magical(request: AuthenticatedRequest[AnyContent]) {
def folderMap = request.magic.fMap
def documentMap = request.magic.dMap
}
}
However, I don't really get the benefit of an implicit this way:
def testing = Authenticated { implicit request =>
import services.Helper._
request.magic.home.folders // doesn't compile
request.magic.home.folders(Magical(request).ffMap) // compiles, but not implicitly
Ok("testing 123")
}
Through an import statement?
One possibility I considered was through an import statement within the controller. Here, the request has a MagicNotebook object in scope that I would like to use as an implicit variable.
def testing = Authenticated { implicit request =>
import request.magic._
request.magic.home.folders // implicit map is a parameter to the `folder` method
Ok("testing 123")
}
Through a companion trait?
Here, I create a companion trait that is mixed into the Authenticate trait that includes the two maps of the MagicNotebook object into scope of the controller.
trait Magic {
implicit def folderMap[A](implicit request: AuthenticatedRequest[A]) =
request.magic.fMap
implicit def docMap[A](implicit request: AuthenticatedRequest[A]) =
request.magic.dMap
}
My preference is the companion trait solution, but I was wondering if there might be a better way that I overlooked. I ended up re-writing methods that use the implicit variable, to use the MagicNotebook's two maps instead of whole object as implicit parameters.
But again, I was wondering if there might be a better way.
I am quite partial to package objects for this sort of thing. See What's New in Scala 2.8: Package Objects for a description. Package objects effectively allow you to put implicit classes into a package, which you can't otherwise do.
However, the main snag with this approach is that you can't split the definition of an object across multiple source files, so because the implicit classes need to be defined within the package object, they also need to be all in the same source file. If you have many implicit classes you wish to have imported, this can result in a large and unwieldy source file. However, that in itself is a sign that you have a “package god object” which should be split.
One of the ways I know of defining implicits is by using Package Objects.
package implicitIdiomatic {
implicit def nullableLongToOption(l:java.lang.Long) = Option(l)
}
}
package implicitIdiomatic
class ImplicitIdiomaticTest{
val l:Long = 1
longOpt(l)
def longOpt(l:Option[Long]) = l match {case Some(l1) => println(l1); case None => println("No long")}
}
Kind of useless example but hope you get the idea. Now when longOpt gets l, it is converted to Option[Long] using the implicit.
As long as you are working in the same package as defined by the package object you don't need the import statement.