1

I`ve found some questions that are very close to my question (e.g. Play Framework / Scala: abstract repository and Json de/serialization) but they didnt solve my problem.

What I`m trying to achieve is an abstraction of my CRUD DAO for the common crud operations.

I build a GenericMongoDaoActor for that:

abstract class GenericMongoDaoActor[T <: Entity: Writes](implicit inj:Injector, implicit val f:Format[T]) extends Actor with Injectable {
  protected val db = inject[DefaultDB]
  protected val collectionName: String
  protected val collection:JSONCollection

  //set to None to use fallback
  def defaultSelector(obj:T):Option[JsObject] = None
  def fallbackSelector(obj:T) = Json.obj("_id" -> Json.obj("$elemMatch" -> obj._id))

  protected def find(jsObject: JsObject) = {
    val currentSender = sender
    val futureOption = collection
      .find(jsObject)
      .cursor[T](ReadPreference.primaryPreferred)
      .headOption

    futureOption.mapTo[Option[T]].flatMap {
      case Some(pobj) =>
        currentSender ! Some(pobj)
        Future{pobj}
      case None =>
        currentSender ! None
        Future{None}
    }
  }

  protected def save(obj:T):Unit = {
    update(obj, true)
  }

  protected def update(obj:T):Unit = {
    update(obj, false)
  }

  private def update(obj:T, upsert: Boolean):Unit = {
    val selector = defaultSelector(obj) match {
      case None => fallbackSelector(obj)
      case Some(sel) => sel
    }
    collection.update(
      selector,
      obj,
      GetLastError.Default,
      upsert).onComplete {
      case Failure(e) => Logger.error("[" + this.getClass.getName + "] Couldn`t update " + obj.getClass.getName + ": " + Json.prettyPrint(Json.toJson(obj)), e)
      case Success(lastError) => //currentSender ! lastError todo: do something with lastError
    }
  }

  def findAll() = {
    collection.find(Json.obj()).cursor[T](ReadPreference.primaryPreferred).collect[List]()
  }

}

The DAOActor handles Entities that inherit abstract class "Entity":

abstract class Entity {
  val _id: BSONObjectID
}

Currently there are 2 classes that inherit Entity..

As you can see my DOAActor is already context bound to look for Writes[T] in scope..

abstract class GenericMongoDaoActor[T <: Entity: Writes]

When I try to build my project like that, it complains that there are no OWrites given to serialize "obj" of type "T" in the update method.

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

collection.update( <-------------

I couldnt find a way to solve this issue. Please let me know if you can.

Community
  • 1
  • 1
heiningair
  • 441
  • 1
  • 6
  • 23

2 Answers2

0

I had similar problems when I migrated from an earlier version of ReactiveMongo. What worked for me was sprinkling around some .as[JsObject] conversions in the various calls to the ReactiveMongo API.

So if before I had:

 collection.update(
  selector,
  obj,
  ...
)

I replaced it with:

collection.update(
  selector,
  obj.as[JsObject],
  ...
)

This seemed to be sufficient, although I am supplying the necessary JSON converter(s) in a slightly different way to you; subclasses of my abstract class have to implement an implicit val fmt:Format[T] member. I doubt whether that is important, but it is an approach that seems to be working :-)

millhouse
  • 9,817
  • 4
  • 32
  • 40
  • That solved my problem. Thanks a lot. I still dont get why it complains that it needs owrites or oformat on top.. – heiningair Nov 09 '15 at 22:10
-1

You need to use OWrites and OFormat instead of Writes and Format. I know OWrites extends Writes and OFormat extends Format, but the reactivemongo version you are using is waiting for OWrites and OFormat, not its super types.

David
  • 179
  • 7
  • That's not possible to use `Writes` instead of `OWrites`, as the specificity of writing a structure corresponding to expected BSON document has to be enforce with `JsObject`, not `JsValue` (result of `Writes`). – cchantep Nov 10 '15 at 08:56
  • @cchantep I said "use OWrites instead of Writes". The use of .as[JsObject] is a hack, not a solution. The newest versions of play-reactivemongo use OWrites, OFormat, etc. I had the same error. Please, read the error. – David Nov 10 '15 at 09:37