Reputation: 1091
Implicit parameters should be easy, but so far they're not.
I've been using ReactiveMongo to save and retrieve data in my Scala / Play 2.4 app. For awhile, I've been doing saves within my Controller, but I want to move the code to the companion object of the entity being saved. And that's where the trouble has begun.
Here are the relevant bits of my Controller, demonstrating how things did work:
package controllers
...
import model.Destination
import model.Destination.DestinationBSONReader
import scala.concurrent.ExecutionContext.Implicits.global
...
def add = Action { implicit request =>
Destination.destinationForm().bindFromRequest.fold(
formWithErrors => {
implicit val helper = sfh(formWithErrors)
BadRequest(views.html.addDestination(formWithErrors))
},
destinationData => {
Destination.mongoCollection.insert(destinationData)
...
Redirect("/destinations").flashing("success" -> s"The destination ${destinationData.name} has been created")
}
}
)
}
You can imagine a form being submitted with data that populated a "Destination", which is then saved to Mongo. The Destination object is imported, as is the scala ExecutionContext. My "Destination" companion object has an instance of BSONDocumentWriter[Destination] (which is required implicitly by the mongoCollection.insert() call) like so:
object Destination {
...
implicit object DestinationBSONWriter extends BSONDocumentWriter[Destination] {
override def write(destination: Destination): BSONDocument = {
val dbId = if (destination.id.isDefined) { destination.id.get } else { BSONObjectID.generate.stringify }
destination.newId = dbId
BSONDocument(
"id" -> dbId,
... lots of other key/value pairs,
"name" -> destination.name)
}
}
...
}
Now, I want to move that mongoCollection.insert(destinationData) call to that same "Destination" object; controllers really shouldn't be talking to datastores. So I created a simple method, which no matter what I do causes compilation errors:
def create(destination: Destination) = {
Destination.mongoCollection.insert(destination)
}
^- compile fails; "could not find implicit value for parameter writer: reactivemongo.bson.BSONDocumentWriter[model.Destination]"
So I added imports to the top of the class, since the Scala compiler is supposed to look at imports while searching for implicit:
import model.Destination.DestinationBSONWriter
import scala.concurrent.ExecutionContext.Implicits.global
^- same compilation error
So I decided to pass the implicit parameters explicitly:
def create(destination: Destination) = {
Destination.mongoCollection.insert(destination)(writer = DestinationBSONWriter, ec=global)
}
^- That one causes the compiler to just hang, and I need to restart activator.
I'm baffled. That implicit parameter is right there in the same object, but it's not being detected by the compiler. How am I supposed to use it?
Upvotes: 2
Views: 73
Reputation: 1091
After a day's worth of looking into this, there is clearly a problem with SBT. For whatever reason it's decided to hang whenever it should be successfully compiling my code.
Upvotes: 0