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?
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With