Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

No implementation for OWrites and Reads was bound in Scala Play app

I have multiple model classes which all share the same properties. For that very reason, I created a trait, e.g.:

trait Player extends Temp {

  val gameId: BSONObjectID

  val personalDetails: abc.PersonalDetails // <- comes from shared library

}

case class FootballPlayer(var _id: Option[BSONObjectID] = None,
                         gameId: BSONObjectID,
                         personalDetails: abc.PersonalDetails,
                         var created: Option[DateTime] = None,
                         var updated: Option[DateTime] = None
                        ) extends Player

case class VideogamePlayer(var _id: Option[BSONObjectID] = None,
                         gameId: BSONObjectID,
                         personalDetails: abc.PersonalDetails,
                         var created: Option[DateTime] = None,
                         var updated: Option[DateTime] = None
                        ) extends Player

All of these models, have as a companion object play.api.libs.json.Reads and play.api.libs.json.OWrites defined.

For example:

object FootballPlayer {

  import play.api.libs.functional.syntax._
  import play.api.libs.json.Reads._
  import play.api.libs.json._
  import reactivemongo.play.json.BSONFormats.BSONObjectIDFormat

  implicit val footballPlayerReads: Reads[FootballPlayer] = (
    (__ \ "_id").readNullable[BSONObjectID].map(_.getOrElse(BSONObjectID.generate)).map(Some(_)) and
      (__ \ "gameId").read[BSONObjectID] and
      (__ \ "personalDetails").read[abc.PersonalDetails] and
      (__ \ "created").readNullable[DateTime].map(_.getOrElse(new DateTime())).map(Some(_)) and
      (__ \ "updated").readNullable[DateTime].map(_.getOrElse(new DateTime())).map(Some(_))
    ) (FootballPlayer.apply _)


  implicit val sharedPersonalDetailsWrites: Writes[abc.PersonalDetails] = abc.PersonalDetails.sharedPersonalDetailsWrites

  implicit val footballPlayerWrites: OWrites[FootballPlayer] = (
    (__ \ "_id").writeNullable[BSONObjectID] and
      (__ \ "gameId").write[BSONObjectID] and
      (__ \ "personalDetails").write[abc.PersonalDetails] and
      (__ \ "created").writeNullable[DateTime] and
      (__ \ "updated").writeNullable[DateTime]
    ) (unlift(FootballPlayer.unapply))

}

Now I want to store them in different collections, but I want to have only one DAO, so I implemented the following:

trait PlayerDAO[T <: Player] {

  def findById(_id: BSONObjectID)(implicit reads: Reads[T]): Future[Option[T]]

  def insert(t: T)(implicit writes: OWrites[T]): Future[T]

}

class MongoPlayerDAO[T <: Player] @Inject()(
                                           playerRepository: PlayerRepository[T]
                                         ) extends PlayerDAO[T] {

  def findById(_id: BSONObjectID)(implicit reads: Reads[T]): Future[Option[T]] = playerRepository.findById(_id)

  def insert(t: T)(implicit writes: OWrites[T]): Future[T] = playerRepository.insert(t).map(_ => t)

}

Then, I have the following repository:

class PlayerService[T <: Player] @Inject()(playerDAO: PlayerDAO[T])(implicit reads: Reads[T], writes: OWrites[T]) {

  def findById(_id: BSONObjectID): Future[Option[T]] = playerDAO.findById(_id)


  def save(t: T): Future[T] = playerDAO.save(t)

}

My module looks as follows:

class PlayerModule extends AbstractModule with ScalaModule {

  def configure() {
    bind[PlayerDAO[FootballPlayer]].to[MongoPlayerDAO[FootballPlayer]]
    bind[PlayerDAO[VideogamePlayer]].to[MongoPlayerDAO[VideogamePlayer]]
    // ...
    ()
  }
}

And in my Play controller I inject the following:

import models.FootballPlayer._
import models.VideogamePlayer._ 

class PlayerController @Inject()(
                                 val messagesApi: MessagesApi,
                                 footballPlayerService: PlayerService[FootballPlayer],
                                 videogamePlayerService: PlayerService[VideogamePlayer]
                               ) extends Controller with I18nSupport

However, unfortunately, I get the following exception:

1) No implementation for play.api.libs.json.OWrites was bound. 2) No implementation for play.api.libs.json.OWrites was bound. 3) No implementation for play.api.libs.json.Reads was bound. 4) No implementation for play.api.libs.json.Reads was bound.

How can I fix this?

like image 775
John Doe Avatar asked Apr 23 '17 10:04

John Doe


1 Answers

Probably it might not be able to find the implicit context when the dao injections are made. Try including implicits in the AbstractModule where you define your bindings.

EDIT

Check my solution on git. Here

I have tried to emulate whatever you are trying to do and its working fine.

I am not quite sure what is the problem with your current code as I dont have access to the entire code, but I think it has something to do with the application searching for OWrites and Reads implicit for Player rather than FootballPlayer or VideoGamePlayer

like image 133
Sumeet Sharma Avatar answered Sep 29 '22 13:09

Sumeet Sharma