当后者具有隐式参数

时间:2017-07-16 20:56:12

标签: scala playframework guice reactivemongo

[请原谅我长期提问,我还在学习Scala。]

我试图将通用特征绑定到具有隐式参数的通用impl。这是清理代码:

trait PersistenceService[T <: SomeOtherClass] { 
  def persist(record: T): Future[Unit]
}

class MongoPersistenceService[T <: SomeOtherClass] @Inject()(implicit ec: ExecutionContext, tag: ClassTag[T]) extends PersistenceService[T] {
  val collectionName: String = tag.runtimeClass.getSimpleName
  val databaseName = "someDatabase"

  def db: Future[DefaultDB] = MongoConnectionWrapper.getMongoConnection("mongodb://127.0.0.1", "27017")
                              .flatMap(_.database(databaseName))

  def collection: Future[BSONCollection] = db.map(_.collection(collectionName))

  def persist(record: T): Future[Unit] = {
    val result = for {
      col <- collection
      writeResult <- col.insert(record)
    } yield writeResult
    result.recoverWith {
                         case WriteResult.Code(11000) => throw RecordAlreadyExistsException(record,
                                                                                            "")
                       }.map(_ => ())
  }

  def read(id: BSONObjectID): Future[T] = {
    val query = BSONDocument("_id" -> id)
    val readResult: Future[T] = for {
      coll <- collection
      record <- coll.find(query).requireOne[T]
    } yield record

    readResult.recoverWith {
                             case NoSuchResultException => throw RecordNotFoundException(id)
                           }
  }
}

我使用Play,ReactiveMongo和ScalaGuice(所有最新版本)。所以这是我的主要模块类绑定所有内容:

class Module(env: Environment, config: Configuration) extends AbstractModule with ScalaModule {
  def configure(): Unit = {
    bind[PersistenceService[_]].to[MongoPersistenceService[_]] // Also tried with specific class instead of _ but not working either
  }
}

让我们说我的控制器之一依赖PersistenceService这样:

class PersistenceServiceController @Inject()(val PersistenceService: PersistenceService[Bar], cc ControllerComponents) extends AbstractController(cc) { ... }

模型(你可以猜到)带有读者/作者:

case class Bar() extends SomeOtherClass() {}
object Bar {
  implicit object BarReader extends BSONDocumentReader[Bar] {
    def read(doc: BSONDocument): Bar = { ... }
  }
  implicit object BarWriter extends BSONDocumentWriter[Bar] {
    def write(bar: Bar): BSONDocument = { ... }
  }
}

有了这些东西,我得到了以下运行时异常:

com.google.inject.CreationException: Unable to create injector, see the following errors:
1) No implementation for reactivemongo.bson.BSONDocumentReader<Bar> was bound.
  while locating reactivemongo.bson.BSONDocumentReader<Bar>
    for the 2nd parameter of MongoPersistenceService.<init>(MongoPersistenceService.scala:15)
  at Module.configure(Module.scala:14) (via modules: com.google.inject.util.Modules$OverrideModule -> Module)
2) No implementation for reactivemongo.bson.BSONDocumentWriter<Bar> was bound.
  while locating reactivemongo.bson.BSONDocumentWriter<Bar>
    for the 3rd parameter of persistence.MongoPersistenceService.<init>(MongoPersistenceService.scala:15)
  at Module.configure(Module.scala:14) (via modules: com.google.inject.util.Modules$OverrideModule -> Module)
3) No implementation for scala.reflect.ClassTag<Bar> was bound.
  while locating scala.reflect.ClassTag<Bar>
    for the 5th parameter of MongoPersistenceService.<init>(MongoPersistenceService.scala:15)
  at Module.configure(Module.scala:14) (via modules: com.google.inject.util.Modules$OverrideModule -> Module)

很明显,我的类MongoPersistenceService应该在执行上下文中获取的内容缺少一些方法。我知道,当你用guice正确设置你的东西时,Play有点神奇地提供执行上下文。但在这种情况下,看起来它不起作用。

我该如何解决?

1 个答案:

答案 0 :(得分:0)

我对这个感觉很糟糕,但是找到问题的错误信息非常明显。要解决此问题,我必须手动绑定BSONDocumentReader[Bar]BSONDocumentWriter[Bar]ClassTag[Bar]的impl。

我将代码重构为更简单的代码。 但是想让其他人知道这是什么问题。