@Provides with @Named does not work for declared supertype variables

I am currently exploring the possibilities of Guice and come across strange behavior - when I declare a variable as

@Inject @Named("dragon") Dragon dragon2; 

the injection works as expected, but when I want to declare dragon2 as an interface (it implements the Creature), i. e.

 @Inject @Named("dragon") Creature dragon2; 

I get an error

There is no implementation for warlock.rincewind.creatures.Creature annotated with @com.google.inject.name.Named(value=dragon) been linked.

Here is my provider method:

 @Named("dragon") @Provides public Dragon providesDragon() { Dragon d = new Dragon("Morkeleb"); return d; } 

I know there are many different ways to overcome this (the simplest is changing the type of return to the Creature), but I'm trying to get the reason for this restriction.

+7
java guice
source share
1 answer

Consider, for example:

 interface Creature { } class Dragon implements Creature { } class Dog implements Creature { } public class Kennel { @Inject @Named("foo") Creature c; } public class KennelModule extends Abstract Module { @Override protected void configure() { bind(Dragon.class).annotatedWith(Names.named("foo")); bind(Dog.class).annotatedWith(Names.named("foo")); } } 

How does your injection know if you need to bind Dragon or Dog here?

Can not! Keys for injection are not covariant . Instead, you need to specify the subclass that you want to enter, and bind it to the interface or superclass that you are inserting into. In other words:

 public class KennelModule extends Abstract Module { @Override protected void configure() { bind(Creature.class).annotatedWith(Names.named("foo").to(Dragon.class); } } 

This will give you the behavior you want. Of course, you can also bind injections for Dragon , of course.

+9
source share

All Articles