3

This is my first play 2.0 app, and scala is still pretty new to me, so I'm likely making a mistake somewhere. I'm using a pretty new plugin that bundles Salat and Casbah: https://github.com/leon/play-salat

I've simplified and renamed everything to make it generic.

My view (views/MyController/search.scala.html):

@(modelList:List[models.MyModel])
@main(title = "Search MyModel") {
  <table>
  @for(a <- modelList) {
    <tr><td>@a.field<td>@a.field2</li>
  } 
  </table>
}

My controller (controllers/MyController.scala):

package controllers

import play.api._
import play.api.mvc._
import play.api.data._
import play.api.data.Forms._
import com.mongodb.casbah.Imports._
import models._

object MyController extends Controller {
  def search = Action {
    val modelList = MyModel.all.toList;
    Ok(views.html.MyController.search(modelList))
  }
}

My model: (models/MyModel.scala):

package models

import play.api.Play.current
import java.util.{Date}
import com.novus.salat._
import com.mongodb.casbah.Imports._
import se.radley.plugin.mongodb._
import se.radley.plugin.mongodb.salat._

case class MyModel(
  id: ObjectId = new ObjectId,
  field: String,
  field2: String
)

object MyModel extends SalatDAO[MyModel, ObjectId](collection = getCollection("mycollection")) {
  def all = find(MongoDBObject())
}

And I'm getting this error:

ClassCastException: models.MyModel cannot be cast to models.MyModel

Which doesn't make much sense to me--has anyone run into something like this?

Full stack trace:

play.core.ActionInvoker$$anonfun$receive$1$$anon$1: Execution exception [[ClassCastException: models.MyModel cannot be cast to models.MyModel]]
at play.core.ActionInvoker$$anonfun$receive$1.apply(Invoker.scala:82) [play_2.9.1.jar:2.0]
at play.core.ActionInvoker$$anonfun$receive$1.apply(Invoker.scala:63) [play_2.9.1.jar:2.0]
at akka.actor.Actor$class.apply(Actor.scala:290) [akka-actor.jar:2.0]
at play.core.ActionInvoker.apply(Invoker.scala:61) [play_2.9.1.jar:2.0]
at akka.actor.ActorCell.invoke(ActorCell.scala:617) [akka-actor.jar:2.0]
at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:179) [akka-actor.jar:2.0]
Caused by: java.lang.ClassCastException: models.MyModel cannot be cast to models.MyModel
at views.html.MyController.search$$anonfun$apply$1.apply(search.template.scala:25) ~[classes/:na]
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:194) ~[scala-library.jar:0.11.2]
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:194) ~[scala-library.jar:0.11.2]
at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59) ~[scala-library.jar:0.11.2]
at scala.collection.immutable.List.foreach(List.scala:45) ~[scala-library.jar:0.11.2]
at scala.collection.TraversableLike$class.map(TraversableLike.scala:194) ~[scala-library.jar:0.11.2]
HEX
  • 1,647
  • 2
  • 15
  • 29
Eve Freeman
  • 32,467
  • 4
  • 86
  • 101

1 Answers1

3

I think the problem here is that your MyModel collection object

object MyModel extends SalatDAO[MyModel, ObjectId](collection = getCollection("mycollection")) {
  def all = find(MongoDBObject())
}

Is what is being imported in your template.

I would try the following:

package models

import play.api.Play.current
import java.util.{Date}
import com.novus.salat._
import com.mongodb.casbah.Imports._
import se.radley.plugin.mongodb._
import se.radley.plugin.mongodb.salat._

case class MyModel(
  id: ObjectId = new ObjectId,
  field: String,
  field2: String
)

object MyModelDAO extends SalatDAO[MyModel, ObjectId](collection = getCollection("mycollection")) {
  def all = find(MongoDBObject())
}

Case classes already come with companion objects. In this case a MyModel companion class is generated by scala for you. The object extending the properly typed SalatDAO is also named MyModel. You would have to look at the bytecode generated for the case class and the MyModel extends SalatDAO[MyModel, ObjectId] classes to find out what the generated class name is, I think it would be models.MyObject$ for your case class. But if you name it differently, then you should get the result you are looking for.

Eve Freeman
  • 32,467
  • 4
  • 86
  • 101
Jack Viers
  • 320
  • 2
  • 12
  • Yeah, I suspected it might have been something with the companion object, but the example shows this sort of configuration (https://github.com/leon/play-mongodb/blob/master/sample/app/models/User.scala). I made your change, and got the same error--ended up needing to restart Play!, apparently it doesn't recompile that sort of thing properly. In any case, thanks much! – Eve Freeman Apr 13 '12 at 01:07
  • My bad, I'm quite new to scala, didn't think it would matter that you put the DAO methods inside the companion object. I Thought it all would get compiled down to a static class. I'll change the documentation. – Leon Radley Apr 13 '12 at 14:26
  • I guess the problem is that the companion object extends SalatDAO. Of course you can put stuff into a case classes companion object, but it usually doesn't extend anything. – Marius Soutier Apr 13 '12 at 14:56
  • I'm not certain precisely why the error occurs. Case class companion objects can extend preexisting objects of the same name - the predefined object simply receives the apply and unapply methods necessary from the generated case class companion object. I think that it may actually have to do with the fact that SalatDAO is generically typed. I'll investigate the matter further and think on it some more and get back to you. – Jack Viers Apr 14 '12 at 02:26
  • Yeah, the fix was temporary. I need to restart play to make it work again, each time I make a change to the view or model file. – Eve Freeman Apr 21 '12 at 01:37