代码之家  ›  专栏  ›  技术社区  ›  zoran jeremic

如何在Scala Guice中绑定一个扩展特性的类和一个monadic类型

  •  0
  • zoran jeremic  · 技术社区  · 4 年前

    我创建了一个简单的Scala-Play应用程序,它具有一元类型的特性,它们各自的实现绑定在Module中,配置为:

    class Module extends AbstractModule {
    
        override def configure() = {
           bind(new TypeLiteral[UserDAO[DBIO]](){}).to(classOf[UserDAOImpl])
           bind(new TypeLiteral[UserService[Future]](){}).to(classOf[UserServiceImpl[Future, DBIO]])
        }
    }
    

    这些特征和实现是:

    ///TRAITS
    //UserDAO.scala
    package models
    
    trait UserDAO[DB[_]] {
      def get(userId: Long): DB[Option[User]]
    }
    
    //UserService.scala
    package services
    
    import resources.UserResponse
    import services.response.ServiceResponse
    
    trait UserService[F[_]] {
      def findUserById(id: Long): F[ServiceResponse[UserResponse]]
    }
    
    
    ///IMPLEMENTATIONS
    //UserDAOImpl.scala
    package dao
    
    import models.{DataContext, User, UserDAO}
    import play.api.db.slick.DatabaseConfigProvider
    import slick.dbio.{DBIO => SLICKDBIO}
    import javax.inject.Inject
    import scala.concurrent.ExecutionContext
    
    class UserDAOImpl @Inject()(
         protected val dbConfigProvider: DatabaseConfigProvider,
         val context: DataContext
        )(
         implicit executionContext: ExecutionContext
        ) extends UserDAO[SLICKDBIO] {
    
    import context.profile.api._
    
    override def get(userId: Long): SLICKDBIO[Option[User]] = context.Users.filter(_.id === userId).result.headOption
    }
    
    
    //UserServiceImpl.scala
    package services
    
    import resources.Mappings.UserToResponseMapping
    import cats.Monad
    import cats.implicits._
    import models.{DatabaseManager, UserDAO}
    import resources.{NoModel, UserResponse}
    import services.response.ServiceResponse
    import util.Conversions.{errorToServiceResponse, objectToServiceResponse}
    import javax.inject.Inject
    
    class UserServiceImpl[F[_]: Monad, DB[_]: Monad]@Inject()(userRepo: UserDAO[DB],
                                                   dbManager: DatabaseManager[F, DB]) 
       extends UserService[F] {
    
       override def findUserById(id: Long): F[ServiceResponse[UserResponse]] = {
         for {
            user <- dbManager.execute(userRepo.get(id))
         } yield user match {
            case Some(user) =>user.asResponse.as200
            case None => NoModel(id).as404
         }
       }
     }
    

    但是,这无法注入依赖项,并引发以下错误:

    play.api.UnexpectedException: Unexpected exception[CreationException: Unable to create injector, see the following errors:
    
    1) models.UserDAO<DB> cannot be used as a key; It is not fully specified.
      at services.UserServiceImpl.<init>(UserServiceImpl.scala:13)
      at Module.configure(Module.scala:35) (via modules: com.google.inject.util.Modules$OverrideModule -> Module)
    
    2) models.DatabaseManager<F, DB> cannot be used as a key; It is not fully specified.
      at services.UserServiceImpl.<init>(UserServiceImpl.scala:13)
      at Module.configure(Module.scala:35) (via modules: com.google.inject.util.Modules$OverrideModule -> Module)
    
    3) cats.Monad<F> cannot be used as a key; It is not fully specified.
      at services.UserServiceImpl.<init>(UserServiceImpl.scala:13)
      at Module.configure(Module.scala:35) (via modules: com.google.inject.util.Modules$OverrideModule -> Module)
    

    这个问题可能与这个问题有关 How to bind a class that extends a Trait with a monadic type parameter using Scala Guice? ,在我的解决方案中,我应用了建议的答案,但仍然失败了。

    有什么建议吗?

    0 回复  |  直到 4 年前
        1
  •  0
  •   Gaël J    4 年前

    如果您查看stacktrace,您可以看到当Guice想要创建 UserServiceImpl :

    ... at services.UserServiceImpl.<init> ...
    

    我怀疑Guice在尝试创建这个类时不知道要“注入”什么。它无法推断必须注入 UserDao[DBIO] 例如,它只知道必须注入 UserDao[DB] 具有 DB 是未指明的东西。

    如何解决这个问题,我不能确定,但我会研究其中一个:

    • 为添加“混凝土”类 UserServiceImpl 并将其绑定,而不是通用的(如 class UserServiceFutureDBIO )
    • 手动实例化 UserServiceImpl 以及绑定到实例,而不是绑定到类并让Guice实例化它
    推荐文章