Scala Dependency injection with generic class

2020-05-02 04:17发布

问题:

Using Guice in Scala, I'm trying to reproduce the following Java code.

Foo interface and class declaration:

public interface Foo[T] {}
public class FooImpl[T] implements Foo[T] {}

Guice binding code:

bind(Foo.class).to(FooImpl.class);

And one use example would be;

@Inject
public class Bar(Foo<String> foo) {}

In scala, my first bet was:

bind(classOf[Foo]).to(classOf[FooImpl])

But it's complaining about 'Type Foo takes type parameter' How do I achieve this in scala?

Thank you

回答1:

Your question has an error and thus it allows you for a wrong answer.

Let's first fix your concept idea. Having trait

trait Foo[T] { def hello: T }

works just fine. But then, the specific classes extending this trait will be, f.e.:

class FooImpl1 extends Foo[Int] { override def hello: Int = 42 }
class FooImpl2 extends Foo[String]{ override def hello: String = "test" }

And they could NOT be:

class FooImpl[Int] extends Foo[Int] { override def hello: Int = 42 }
class FooImpl[String] extends Foo[String]{ override def hello: String = "test" }

Because then, the Int or String is just the NAME for a generic parameter. It could be as well A and B, but you have just confused yourself.


Having this sorted out, you know know that you have FooImpl1 and FooImpl2. They need different names because you can not have two classes named the same in the same scope!

And it is just fine. Because when you :

bind(classOf[X]).to(classOf[Y])

You are telling that whenever your class will call methods of the Interface or Trait X you want to provide the implementation of class Y.

You have to provide a class that you can instantiate! You could not instantiate a class with a generic parameter.

And, to finish, your proper binding would look like this:

bind(new TypeLiteral[Foo[Int]](){}).to(classOf[FooImpl1])
bind(new TypeLiteral[Foo[String]](){}).to(classOf[FooImpl2])