Использование метода fromJSON ModelCompanion в приложении Play вызывает исключение NoSuchMethodException

Я новичок в Scala и пытаюсь сделать свое первое приложение Play 2.0. Я использую:

У меня есть это в моем conf/routes файл:

PUT /newVenue   controllers.Application.createNewVenue

У меня есть это в моем Application.scala файл:

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

И это код для 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)

Чтобы проверить, работает ли это, я отправляю запрос PUT localhost:9000/newVenue с этим JSON в качестве тела:

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

И тогда я получаю эту ошибку:

[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]

Я думаю, что строка, вызывающая ошибку: val newVenue = Venue.fromJSON (request.body.toString).

Кто-нибудь знает, что не так? Я следовал учебному пособию на странице SalatWithPlay2, а также следовал некоторым советам по аналогичным проблемам), но мне пока не повезло.

ОБНОВЛЕНИЕ:

Я нашел обходной путь, хотя это не совсем решение, но, может быть, это полезно для кого-то другого и для понимания того, что является реальным решением.

Если я удалю аннотацию @Key, код класса случая Venue будет выглядеть так:

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

И тогда я получаю эту другую ошибку:

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

И если вместо использования ObjectId я использую Long, например, код выглядит так:

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

И я не получаю ошибки!

Таким образом, NoSuchMethodException, очевидно, связано с аннотацией @Key, связанной с _id. Я также попытался переименовать venueId в _id, и появилась та же ошибка NoSuchMethodException. Поэтому возникает вопрос: почему я не могу использовать аннотацию @Key, чтобы сказать, какой из моих атрибутов отображается на идентификатор объекта документа в базе данных mongo? Кроме того, обычные целые числа не могут быть автоматически преобразованы в экземпляры ObjectId по какой-то другой причине.

Спасибо!

2 ответа

Решение

Итак, я нашел в чем проблема.

Атрибуты Json, отправленные в теле запроса, должны соответствовать именам атрибутов документа mongodb, а не атрибутам объекта Scala.

Поэтому, если мой класс Venue определен следующим образом: case class Venue( @Key("_id") val venueId:ObjectId, var playlist:Playlist, var isPlaying:Boolean = false)

Json, который я должен отправить в запросе PUT:

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

И НЕ

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

Просто выстрел в темноте, но можете ли вы назвать свой класс объектов чем-то другим? Может быть, к VenueCompanion? Кажется, возможно, что компилятор запутался, к какому объекту обращаться. То есть это не относится к тому классу Venue, который вы хотите. Мне любопытно, если после этого исключение остается прежним.

Другие вопросы по тегам