Не реализована реализация для OWrites и Reads в приложении Scala Play
У меня есть несколько классов моделей, которые имеют одни и те же свойства. По этой причине я создал признак, например:
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
Все эти модели имеют в качестве объекта-компаньона play.api.libs.json.Reads
и play.api.libs.json.OWrites
.
Например:
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))
}
Теперь я хочу хранить их в разных коллекциях, но я хочу иметь только один DAO, поэтому я реализовал следующее:
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)
}
Затем у меня есть следующий репозиторий:
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)
}
Мой модуль выглядит следующим образом:
class PlayerModule extends AbstractModule with ScalaModule {
def configure() {
bind[PlayerDAO[FootballPlayer]].to[MongoPlayerDAO[FootballPlayer]]
bind[PlayerDAO[VideogamePlayer]].to[MongoPlayerDAO[VideogamePlayer]]
// ...
()
}
}
И в моем контроллере Play я добавляю следующее:
import models.FootballPlayer._
import models.VideogamePlayer._
class PlayerController @Inject()(
val messagesApi: MessagesApi,
footballPlayerService: PlayerService[FootballPlayer],
videogamePlayerService: PlayerService[VideogamePlayer]
) extends Controller with I18nSupport
Однако, к сожалению, я получаю следующее исключение:
1) Никакой реализации для play.api.libs.json.OWrites был связан. 2) Нет реализация для play.api.libs.json.OWrites был связан. 3) Никакой реализации для play.api.libs.json.Reads был связан. 4) Нет реализация для play.api.libs.json.Reads был связан.
Как я могу это исправить?
Ответы
Ответ 1
Вероятно, возможно, он не сможет найти неявный контекст, когда будут сделаны инъекции dao. Попробуйте включить implicits в AbstractModule, где вы определяете свои привязки.
ИЗМЕНИТЬ
Проверьте мое решение на git. Здесь
Я попытался подражать всему, что вы пытаетесь сделать, и его работоспособность.
Я не совсем уверен, в чем проблема с вашим текущим кодом, поскольку у меня нет доступа ко всему коду, но я думаю, что он имеет какое-то отношение к приложению, ищущему OWrites и Reads, неявным для Player
, а не FootballPlayer
или VideoGamePlayer
Ответ 2
Похоже, вы пытаетесь ввести сериализатор (de), в то время как вы можете просто указать им неявный параметр для своего класса:
class PlayerService[T <: Player](implicit reads: Reads[T], writes: OWrites[T]) @Inject()(playerDAO: PlayerDAO[T])
или даже проще (писать, но имеет строго то же значение):
class PlayerService[T <: Player: Reads: OWrites] @Inject()(playerDAO: PlayerDAO[T])
Так как Reads[T]
и OWrites[T]
не реализованы в виде модулей, Guice не может правильно их внедрить. Тем не менее, они все еще могут быть нормальными параметрами для вашего класса.