Search code examples
scalaplayframeworkreactivemongoplay-reactivemongo

No Json serializer as JsObject found for type model.User. Try to implement an implicit OWrites or OFormat for this type


I'm using Play framework with Scala and Reactive Mongo to save an object into my mongodb database. Following this http://reactivemongo.org/releases/0.10/documentation/bson/usage.html I came up with the following code:

import java.util.Date

import com.google.inject.Inject
import model.User
import play.modules.reactivemongo.ReactiveMongoApi
import play.modules.reactivemongo.json.collection.JSONCollection
import reactivemongo.bson.{BSONDocument, BSONDocumentReader, BSONDocumentWriter, BSONObjectID}
import play.modules.reactivemongo.json._, ImplicitBSONHandlers._
import json.JsonFormatters._

class UserRepository @Inject() (val reactiveMongoApi : ReactiveMongoApi) {

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

  def save(user: User) = {
    users.insert(user)
  }

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

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

I created my implicit writers to convert to a BsonDocument, so I was expecting it to be properly converted and saved into the database.

However, when I compile, I get:

UserRepository.scala:18: No Json serializer as JsObject found for type model.User. Try to implement an implicit OWrites or OFormat for this type.
[error] Error occurred in an application involving default arguments.
[error]     users.insert(user)

I'm importing necessary packages as mentioned in No Json serializer as JsObject found for type play.api.libs.json.JsObject. I'm also importing json.JsonFormatters._ which includes:

implicit val userWrites : Format[User] = Json.format[User]

Yet, it's still returning the same error telling me it can't convert from JsObject to User. I fail to see where is the JsObject here, considering my User entity is just a case class with 5 fields.

case class User(var id: BSONObjectID, var name: String, var email: String, var companyName: String, var created: Date) {
}

Any ideas? What am I missing?


Solution

  • You are using BSONObjectID, and you do not have implicit OFormat for that type. Try this:

    implicit val format = Json.format[User]    
    implicit val userFormats = new OFormat[User] {
    override def reads(json: JsValue): JsResult[User] = format.reads(json)
    
    override def writes(o: User): JsObject = format.writes(o).asInstanceOf[JsObject]
    }
    

    Typically, BSONObjectID (_id) does not make any sense in the application. Therefore, you should not use it. If you need an Id, for example as a running number, for users, you can define a new field. This is an example: https://github.com/luongbalinh/play-mongo/blob/master/app/models/User.scala