Search code examples
genericsscaladependency-injectionguicecode-injection

Guice And Scala - Injection on Generics Dependencies


I'm trying to create a binding of a generic trait using Guice

See how the trait is defined

trait Repository[T]

See the trait implementation

class DomainRepository extends Repository[Domain]

My configure method in DomainPersistenceModule is:

def configure() {
   bind(classOf[Repository[Domain]])
     .annotatedWith(classOf[DomainDependency])
     .to(classOf[DomainRepository])
     .in(Scopes.SINGLETON)
}

The variable whose dependence will be injected is:

  @Inject
  @DomainDependency
  var repository:Repository[Domain] = _

The injection occurs here:

val injector:Injector = Guice.createInjector(new PersistenceModule())

val persistenceService:PersistenceService =
        injector.getInstance(classOf[DomainPersistenceService])

The error is:

Caused by: com.google.inject.ConfigurationException: Guice configuration errors:

1) No implementation for repository.Repository<domain.Domain> annotated with @module.annotation.DomainDependency() was bound.
  while locating repository.Repository<domain.Domain> annotated with @module.annotation.DomainDependency()
    for field at service.persistence.DomainPersistenceService.repository(DomainPersistenceService.scala:19)
  while locating service.persistence.DomainPersistenceService

Am I missing something? Thanks in advance


Solution

  • You need a TypeLiteral binding like this:

    bind(new TypeLiteral[Repository[Domain]] {})
     .annotatedWith(classOf[DomainDependency])
     .to(classOf[DomainRepository])
     .in(Scopes.SINGLETON)
    

    TypeLiteral is a special class that allows you to specify a full parameterized type. Basically, you can't instantiate a class with a generic type parameter.

    Also, take a look at this answer.

    See "How to inject class with generic type?" in the Guice FAQ.