我怎样才能找到播放表单类型(用于处理控制器中的 post 请求)以映射包含 BSON ObjectID 类型的 class?

How can I find a play form type (for handling post requests in controller) in order to map a class containing BSONObjectID type?

我正在使用 Play Framework (2.2.6) / scala / mongoDB 开发 Web 应用程序,我遇到了 reactivemongo.bson.BSONObjectID 的问题。 (我是 ReactiveMongo 和 Scala 的初学者)

我的控制器包含此代码:

val actForm = Form(tuple(
    "name" -> optional(of[String]),
    "shortcode" -> optional(of[String]),
    "ccam" -> mapping(
        "code" -> optional(of[String]),
        "description" -> optional(of[String]),
        "_id" -> optional(of[BSONObjectID])
    )(CCAMAct.apply)(CCAMAct.unapply)
));

def addAct = AsyncStack(AuthorityKey -> Secretary) { implicit request =>
    val user = loggedIn
    actForm.bindFromRequest.fold(
    errors => Future.successful(BadRequest(errors.errorsAsJson)), {
      case (name, shortcode, ccam) =>

        val newact = Json.obj(
          "id" -> BSONObjectID.generate,
          "name" -> name,
          "shortcode" -> shortcode,
          "ccam" -> ccam
        )

        settings.update(
            Json.obj("practiceId" -> user.practiceId.get),
            Json.obj("$addToSet" -> Json.obj("acts" -> Json.obj("acte" -> newact)))
        ).map { lastError => Ok(Json.toJson(newact)) }
    })
}

CCAMAct class 定义如下:

import models.db.Indexable
import play.api.libs.json._
import reactivemongo.bson.BSONObjectID
import reactivemongo.api.indexes.{Index, IndexType}
import models.db.{MongoModel, Indexable}
import scala.concurrent.Future
import play.modules.reactivemongo.json.BSONFormats._
import models.practice.Practice
import play.api.libs.functional.syntax._

case class CCAMAct(code:Option[String],
                   description:Option[String],
                   _id: Option[BSONObjectID] = None) extends MongoModel {}

object CCAMAct extends Indexable {

    private val logger = play.api.Logger(classOf[CommonSetting]).logger

    import play.api.Play.current
    import play.modules.reactivemongo.ReactiveMongoPlugin._
    import play.modules.reactivemongo.json.collection.JSONCollection
    import scala.concurrent.ExecutionContext.Implicits.global

    def ccam: JSONCollection = db.collection("ccam")

    implicit val ccamFormat = Json.format[CCAMAct]

    def index() = Future.sequence(
        List (
            Index(Seq("description" -> IndexType.Text))
        ).map(ccam.indexesManager.ensure)
    ).onComplete { indexes => logger.info("Text index on CCAM ends") }
}

因此编译器向我抛出这个错误:

Cannot find Formatter type class for reactivemongo.bson.BSONObjectID. Perhaps you will need to import play.api.data.format.Formats._
       "_id" -> optional(of[BSONObjectID])
                           ^

(当然我已经导入了"play.api.data.format.Formats._")

我还尝试根据网络上类似帖子的回答添加自定义格式化程序。

object Format extends Format[BSONObjectID] {

    def writes(objectId: BSONObjectID): JsValue = JsString(objectId.stringify)

    def reads(json: JsValue): JsResult[BSONObjectID] = json match {
        case JsString(x) => {
            val maybeOID: Try[BSONObjectID] = BSONObjectID.parse(x)
            if(maybeOID.isSuccess) 
                JsSuccess(maybeOID.get) 
            else {
                JsError("Expected BSONObjectID as JsString")
            }
        }
        case _ => JsError("Expected BSONObjectID as JsString")
    }
}

...没有任何成功。

[已更新 POST]
最后我无法找到播放表单类型(用于处理控制器中的 POST 请求)以映射包含 BSONObjectID 类型的 class...

有人知道解决此问题的干净解决方案吗?

ReactiveMongo 的 BSON 类型的 JSON FormatFormats._ 中不是由 Play 本身提供的,而是由 Play 的 ReactiveMongo 插件提供的。

import play.modules.reactivemongo.json.BSONFormats._