Как связать класс, который расширяет Trait с параметром монадического типа, используя Scala Guice? - PullRequest
2 голосов
/ 19 июня 2019

Мне нужно привязать реализацию этой черты:

trait ClientRepository[F[_]] {
  def list(): F[Iterable[ClientDTO]]
}

к этой реализации:

import cats.effect.IO

@Singleton
class ClientRepositoryImpl @Inject()(db: OldDataBase, c: IOContextShift)
    extends ClientRepository[IO] {

  override def list(): IO[Iterable[ClientDTO]] = ???
}

Я использую Scala Play! v2.7.2 и Scala v2.12.8, с scala-guice v4.2.1. Чтобы привязать черту к ее реализации, я хотел бы сделать что-то подобное в моем Module.scala:

class Module(environment: Environment, configuration: Configuration)
    extends AbstractModule
    with ScalaModule {

  override def configure() = {

    bind[ClientRepository].to[ClientRepositoryImpl[IO]].in[Singleton]

  }
}

И ошибка, которую я получаю:

[error] app/Module.scala:37:9: kinds of the type arguments (ClientRepository) do not conform to the expected kinds of the type parameters (type T).
[error] ClientRepository's type parameters do not match type T's expected parameters:
[error] trait ClientRepository has one type parameter, but type T has none
[error]     bind[ClientRepository].to[ClientRepositoryImpl[IO]].in[Singleton]
[error]         ^
[error] app/Module.scala:37:31: ClientRepositoryImpl does not take type parameters
[error]     bind[ClientRepository].to[ClientRepositoryImpl[IO]].in[Singleton]
[error]                               ^
[error]

Я также пробовал:

bind[ClientRepository[IO]].to[ClientRepositoryImpl].in[Singleton]

Module.scala:37:9: kinds of the type arguments (cats.effect.IO) do not conform to the expected kinds of the type parameters (type T).
[error] cats.effect.IO's type parameters do not match type T's expected parameters:
[error] class IO has one type parameter, but type T has none
[error]     bind[ClientRepository[IO]].to[ClientRepositoryImpl].in[Singleton]
[error]         ^

и bind[ClientRepository[IO[_]]].to[ClientRepositoryImpl].in[Singleton]

Module.scala:37:27: cats.effect.IO[_] takes no type parameters, expected: one
[error]     bind[ClientRepository[IO[_]]].to[ClientRepositoryImpl].in[Singleton]
[error]                           ^

Как правильно это исправить?

1 Ответ

2 голосов
/ 19 июня 2019

Я нашел правильное решение, используя TypeLiteral от Guice, после прочтения этого SO ответа и этого .

Рабочий раствор:

    // In Module.scala configure()
    bind(new TypeLiteral[ClientRepository[IO]] {}).to(classOf[ClientRepositoryImpl])

потому что мы должны предоставить класс, который может быть создан (с параметром типа, который в нашем случае равен IO). TypeLiteral, который является специальным классом, позволяющим указывать полный параметризованный тип, может использоваться для создания фактической привязки к конкретной реализации нашего Repo[F[_]]. Класс с универсальным параметром не может быть создан, но мы можем заставить Guice выбрать конкретный ClientRepository, созданный с параметром типа cats.effect.IO.

И последнее, но не менее важное, если вам нужно ввести черту ClientRepository, вы также должны указать параметр типа. Например:

class ClientResourceHandler @Inject()(
    routerProvider: Provider[ClientRouter],
    clientRepository: ClientRepository[IO]
)

ClientResourceHandler необходимо вызвать репо, поэтому мы вводим его, используя черту ClientRepository[IO] (а не просто ClientRepository).

...