Frage

I'm new to Scala and I'm trying to do my first Play 2.0 application. I'm using:

I have this in my conf/routes file:

PUT /newVenue   controllers.Application.createNewVenue

I have this in my Application.scala file:

def createNewVenue = Action(parse.json) { request =>
    val newVenue = Venue.fromJSON(request.body.toString)
    Venue.insert(newVenue)
    Ok("New Venue Created")
  }

And this is the code for Venue.scala:

import play.api.Play.current
import com.novus.salat._
import com.novus.salat.global._
import com.novus.salat.annotations._
import com.novus.salat.dao._
import com.mongodb.casbah.Imports._
import se.radley.plugin.salat._

object Venue extends ModelCompanion[Venue, ObjectId] {
        val collection = mongoCollection("venues")
        val dao = new SalatDAO[Venue, ObjectId](collection = collection) {}
    }

case class Venue(
        @Key("_id") val venueId:ObjectId,
        var playlist:Playlist, 
        var isPlaying:Boolean = false)

To test if this is working I send a PUT request to localhost:9000/newVenue with this JSON as a body:

{"venueId": 3,"playlist":{"playlistId":2,"currentSongPosition":5},"isPlaying":false}

And then I get this error:

[error] application - 

! @6d7oco1hf - Internal server error, for request [PUT /newVenue] ->

play.core.ActionInvoker$$anonfun$receive$1$$anon$1: Execution exception [[NoSuchMethodException: model.Venue$.apply$default$1()]]
    at play.core.ActionInvoker$$anonfun$receive$1.apply(Invoker.scala:134) [play_2.9.1.jar:2.0.4]
    at play.core.ActionInvoker$$anonfun$receive$1.apply(Invoker.scala:115) [play_2.9.1.jar:2.0.4]
    at akka.actor.Actor$class.apply(Actor.scala:318) [akka-actor.jar:2.0.2]
    at play.core.ActionInvoker.apply(Invoker.scala:113) [play_2.9.1.jar:2.0.4]
    at akka.actor.ActorCell.invoke(ActorCell.scala:626) [akka-actor.jar:2.0.2]
    at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:197) [akka-actor.jar:2.0.2]
Caused by: java.lang.NoSuchMethodException: model.Venue$.apply$default$1()
    at java.lang.Class.getMethod(Class.java:1605) ~[na:1.6.0_37]
    at com.novus.salat.ConcreteGrater.defaultArg(Grater.scala:350) ~[salat-core_2.9.1-1.9.1.jar:1.9.1]
    at com.novus.salat.ConcreteGrater.safeDefault(Grater.scala:360) ~[salat-core_2.9.1-1.9.1.jar:1.9.1]
    at com.novus.salat.ConcreteGrater$$anonfun$6$$anonfun$apply$7.apply(Grater.scala:319) ~[salat-core_2.9.1-1.9.1.jar:1.9.1]
    at com.novus.salat.ConcreteGrater$$anonfun$6$$anonfun$apply$7.apply(Grater.scala:319) ~[salat-core_2.9.1-1.9.1.jar:1.9.1]
    at scala.Option.orElse(Option.scala:218) ~[scala-library.jar:0.11.3]

I think the line triggering the error is val newVenue = Venue.fromJSON(request.body.toString).

Does anyone have a clue of what's wrong? I followed the tutorial in SalatWithPlay2 page and also followed some advices in similar problems), but I had no luck so far.

UPDATE:

I found a workaround, although it's not exactly a solution, but maybe it's helpful for somebody else and for understanding what is the actual solution.

If I remove the annotation @Key, the code of the case class Venue looks like this:

case class Venue(
        val venueId:ObjectId,
        var playlist:Playlist, 
        var isPlaying:Boolean = false)

And then I get this other error:

[RuntimeException: in: unexpected OID input class='net.liftweb.json.JsonAST$JInt', value='3']

And if instead of using ObjectId I use Long for example, the code looks like this:

case class Venue(
        val venueId:Long,
        var playlist:Playlist, 
        var isPlaying:Boolean = false) 

And I get no error!

So the NoSuchMethodException apparently is related to the @Key annotation related to the _id. I also tried to rename venueId to _id and the same NoSuchMethodException error appeared. So the question is: why can't I use the @Key annotation to say which of my attributes maps to the object id of the document in the mongo database? Besides that, regular Integers cannot be automatically converted to ObjectId instances for some other reason.

Thanks!

War es hilfreich?

Lösung 2

So I found what was the problem.

The attributes of the Json sent in the body of the request must match the names of the attributes of the mongodb's document, not the attributes of the Scala object.

So if my class Venue is defined like this: case class Venue( @Key("_id") val venueId:ObjectId, var playlist:Playlist, var isPlaying:Boolean = false)

The Json I have to send in the PUT request is:

{"_id": 3,"playlist":{"playlistId":2,"currentSongPosition":5},"isPlaying":false}

And NOT:

{"venueId": 3,"playlist":{"playlistId":2,"currentSongPosition":5},"isPlaying":false}

Andere Tipps

Just a shot in the dark, but can you try naming your object class to something else? Maybe to VenueCompanion? It seems it is possible the compiler is getting confused on which object to apply to. IE it is not applying to the case class Venue, that you want. I am curious if the exception is still the same afterwards.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top