Использование метода 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. Я также попытался переименовать место проведения Id в _id, и появилась та же ошибка NoSuchMethodException. Итак, возникает вопрос: почему я не могу использовать аннотацию @Key, чтобы сказать, какой из моих атрибутов соответствует идентификатору объекта документа в базе данных mongo? Кроме того, обычные целые числа не могут быть преобразованы автоматически. к экземплярам ObjectId по какой-либо другой причине.

Спасибо!


person Carla    schedule 02.02.2013    source источник
comment
Я обнаружил, что другой вопрос с той же проблемой здесь, но ответа нет. Эта другая проблема тоже выглядит очень похоже, но при попытке перезапустить игру ничего нового не происходит, я все равно получаю ту же ошибку.   -  person Carla    schedule 03.02.2013


Ответы (2)


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

person Nick    schedule 02.02.2013
comment
Спасибо, я попробовал ваше предложение и получил точно такое же исключение и трассировку стека :( - person Carla; 02.02.2013

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

Атрибуты 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}
person Carla    schedule 03.02.2013
comment
ааа, это потому что ты используешь casbah! Извините, я не подумал об этом. Я так привык использовать Reactive Mongo, и вы можете сопоставлять свои объекты с помощью чтения и записи с тем, что вы хотите. По сути, вы можете оставить свой идентификатор места проведения и сделать так, чтобы чтения отображали его на _id. - person Nick; 06.02.2013