3

Here below is again the case class I presented in my previous post... but with the fix suggested by cmbaxter:

case class User(
  id: Option[BSONObjectID],
  name: String,
  addresses: Option[List[BSONObjectID]]
)

object User {
  implicit object UserWriter extends BSONDocumentWriter[User] {
    def write(user: User) = BSONDocument(
      "_id" -> user.id.getOrElse(BSONObjectID.generate),
      "name" -> user.name,
      "addresses" -> user.addresses
    ) 
  }

  implicit object UserReader extends BSONDocumentReader[User] {
    def read(doc: BSONDocument) = User(
      doc.getAs[BSONObjectID]("_id"),
      doc.getAs[String]("name").get,
      doc.getAs[List[BSONObjectID]]("addresses")
    )
  }
}

Now I'm trying to implement a Play controller that validates incoming Json and saves it into the database (MongoDB). Here below is my code:

object Users extends Controller with MongoController {

  private def collection = db.collection[JSONCollection]("users")

  def create = Action.async(parse.json) { request =>
    request.body.validate[User].map { user =>
      collection.insert(user).map { lastError =>
        Logger.debug(s"Successfully inserted with LastError: $lastError")
        Created
      }
    }.getOrElse(Future.successful(BadRequest("invalid json")))
  }
}

The code above does not compile because the compiler doesn't find any Json deserializer:

[error] /home/j3d/Projects/test/app/controllers/Users.scala:44: No Json deserializer found for type models.User. Try to implement an implicit Reads or Format for this type.
[error]     request.body.validate[User].map { user =>
[error]                          ^

Would it be possible to reuse the BSONDocumentWriter and BSONDocumentReader I've defined in the User companion object instead of implementing the Reads and Writes?

Community
  • 1
  • 1
j3d
  • 9,492
  • 22
  • 88
  • 172

2 Answers2

1

No, you can't reuse the BSON document reader/writers as JSON read/writes. However, you can reuse JSON read/writes as BSON document readers/writers. You want to use a JSONCollection to access the database from the play-reactive-mongo-plugin, then rewrite your BSON document reader/writers to be JSON reads/writes. You can see an example of doing this in the play-mongo-knockout activator template:

https://github.com/typesafehub/play-mongo-knockout

James Roper
  • 12,695
  • 46
  • 45
  • Tx, very interesting. Is there any good example of how to deal with lists (e.g. Users.addresses) and compound elements (e.g. a passoword class consisting of hashtext and salt)? – j3d Jan 01 '14 at 20:49
  • Lists should just work... eg (__ \ "someKey").read[List[String]]. As for custom types, define the implicit reads/writes or format for it, eg: implicit lazy val fooReads: Reads[Foo] = ..., and then you can (__ \ "foo").read[Foo] – James Roper Jan 01 '14 at 21:17
  • Thank you very much for your great support! In the meanwhile I've [re]read chapter 8 of book "Play in Action" which covers this topic in detail - I read it 6 months... but it looks like I suffer from alzheimer ;-) – j3d Jan 01 '14 at 22:41
1

if you are still looking for more complex example i just end up after 3 hours with this. It is basic implementation of automatic writes for models , it is validating json requests and storing to collection with 10 lines of code :) You dont need to repeat inserts in controller

https://github.com/MilosMosovsky/play-reactivemongo-models

Milos Mosovsky
  • 2,913
  • 1
  • 16
  • 18