nozik
nozik

Reputation: 327

Injection of annotated generic classes with Guice

I'm trying to inject different versions of the same generic type, so far with no luck. The bindings that I do in the AbstractModule implementation are:

   bind(new TypeLiteral<ConcurrentHashMap<String, Integer>>() {
}).annotatedWith(Names.named("name0")).toProvider(
    ConcurrentHashMap::new).in(Singleton.class);
   bind(new TypeLiteral<ConcurrentHashMap<String, Long>>() {
}).annotatedWith(Names.named("name1")).toProvider(
    ConcurrentHashMap::new).in(Singleton.class);
   bind(new TypeLiteral<ConcurrentHashMap<String, Boolean>>() {
}).annotatedWith(Names.named("name2")).toProvider(
    ConcurrentHashMap::new).in(Singleton.class);
   bind(new TypeLiteral<ConcurrentHashMap<String, Short>>() {
}).annotatedWith(Names.named("name3")).toProvider(
    ConcurrentHashMap::new).in(Singleton.class);

I tried injecting them by simply using:

@Inject @Named("name0") ConcurrentHashMap<String, Integer>;

and so on. However, I get the following error:

1) Unable to create binding for java.util.concurrent.ConcurrentHashMap<java.lang.String, java.lang.Integer> annotated with @com.google.inject.name.Named(value=name0). It was already configured on one or more child injectors or private modules

What am I doing wrong? Thanks!

Upvotes: 2

Views: 1525

Answers (2)

nozik
nozik

Reputation: 327

I found that the problem is with the injector itself. When I use the "Regular" Guice injector (by calling Guice.createInjector(new MyModule()) everything works fine. However, I've been using the netflix governator injector (by calling LifecycleInjector.builder().withModules(new MyModule()).build().createInjector()), which seems to be causing the problem.

Upvotes: 2

Jeff Bowman
Jeff Bowman

Reputation: 95614

The code is fine, and the error message is pretty clear: Check your child injectors and your private modules for any other bindings to @Named("name0") ConcurrentHashMap<String, Integer>. Guice is very careful not to allow bindings for the same key in the same injector, even if the bindings are inaccessible directly from the parent injector due to child injectors or private modules.

You might also consider switching toProvider syntax for

bind(new TypeLiteral<ConcurrentHashMap<String, Integer>>() {
}).annotatedWith(Names.named("name0")).toProvider(
ConcurrentHashMap::new).in(Singleton.class);

to the simpler use of to:

bind(new TypeLiteral<ConcurrentHashMap<String, Integer>>() {})
   .annotatedWith(Names.named("name0"))
   .to(ConcurrentHashMap.class)
   .in(Singleton.class);

...partially because it's more typical of Guice usage, and partially because it may allow Guice to be more permissive with duplicate bindings. (Guice might have a hard time detecting duplicates through the Java 8 translation from ConcurrentHashMap::new to Provider<ConcurrentHashMap>.) Diagnosing the duplicate binding is probably a better idea, though.

Upvotes: 2

Related Questions