当后者具有隐式参数时,如何正确地将特征绑定到其 impl
Posted
技术标签:
【中文标题】当后者具有隐式参数时,如何正确地将特征绑定到其 impl【英文标题】:How to properly bind a trait to its impl when the later one has implicit parameters 【发布时间】:2017-07-16 20:56:12 【问题描述】:[请原谅我问了这么长的问题,我还在学习 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) ...
以及模型(您可能已经猜到)及其隐含的 Reader/Writer:
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】:好吧,我对这个感觉很不好,但是错误消息很明显可以找到问题。为了解决这个问题,我必须手动绑定 BSONDocumentReader[Bar]
、BSONDocumentWriter[Bar]
和 ClassTag[Bar]
的 impl。
我将我的代码重构为更简单的东西。 但想让其他人知道问题出在哪里。
【讨论】:
以上是关于当后者具有隐式参数时,如何正确地将特征绑定到其 impl的主要内容,如果未能解决你的问题,请参考以下文章
如何正确地将 Popup 绑定到 ToggleButton?
Laravel 8:如何使隐式模型绑定路由参数可选而不是抛出 404?