I have a problem using Play 2.5.x and ReactiveMongo Play. I am trying to create a Generic Repository and I have serious problems when serialize and deserialize objects to database. It always give me the following error: No Json deserializer found for type E. Try to implement an implicit Reads or Format for this type.
Here is my generic code:
package repositories.mongo
import javax.inject.Inject
import core.Entity
import play.modules.reactivemongo.ReactiveMongoApi
import reactivemongo.api.QueryOpts
import repositories.Repository
import scala.collection.Seq
import scala.concurrent.{ExecutionContext, Future}
import reactivemongo.play.json._
import play.api.libs.json._
import reactivemongo.play.json.collection.JSONCollection
class MongoRepository[K, E <: Entity[K]] @Inject()(reactiveMongo: ReactiveMongoApi) extends Repository[K, E] {
protected def collection(implicit ec: ExecutionContext) = reactiveMongo.database.map(_.collection[JSONCollection](this.getCollectionName))
protected def getCollectionName: String = {
"users"
}
def getAll(count: Int, skip: Int)(implicit ec: ExecutionContext): Future[Seq[E]] = {
this.collection.flatMap(_.find(Json.obj())
.options(QueryOpts(skipN = skip))
.cursor[E]().collect[Seq[E]](count))
}
def getFilter(count: Int, skip: Int, f: E => Boolean)(implicit ec: ExecutionContext): Future[Seq[E]] = {
this.collection.flatMap(_.find(f)
.options(QueryOpts(skipN = skip))
.cursor[E]().collect[Seq[E]](count))
}
def getById(id: K)(implicit ec: ExecutionContext): Future[Option[E]] = {
this.collection.flatMap(_.find(Json.obj("_id" -> id.toString)).one[E])
}
def create(entity: E)(implicit ec: ExecutionContext): Future[Option[E]] = {
this.collection.flatMap(_.insert(entity)).flatMap(_ => Future.successful(Option(entity)))
}
def updateById(id: K, entity: E)(implicit ec: ExecutionContext): Future[Option[E]] = {
this.collection.flatMap(_.findAndUpdate(Json.obj("_id" -> id.toString), entity)
.map(_.result[E]))
}
def deleteById(id: K)(implicit ec: ExecutionContext): Future[Option[E]] = {
this.collection.flatMap(_.findAndRemove(Json.obj("_id" -> id.toString))
.map(_.result[E]))
}
}
Here is my concrete class that includes the json format serializer.
package core
import play.api.libs.json.Json
trait Entity[K] {
val id: K
}
case class User(
id: String,
name: String,
email: String
) extends Entity[String] {
}
object User {
implicit val jsonFormat = Json.format[User]
}
When you create your MongoRepository
you need to say that E
needs a json Format
. You can do it like this:
class MongoRepository[K, E <: Entity[K]: Format]
// this is the same as
class MongoRespository[K, E <: Entity[K]](implicit formatter: Format[E])