Использование метода fromJSON ModelCompanion в приложении Play вызывает исключение NoSuchMethodException
Я новичок в Scala и пытаюсь сделать свое первое приложение Play 2.0. Я использую:
- Scala 2.9.3
- Play 2.0.4
- SalatWithPlay2 1.1
У меня есть это в моем 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, который вы хотите. Мне любопытно, если после этого исключение остается прежним.