Reputation: 14279
I am using guice for dependency injection and wrote a provider that returns HashMap<String, HashMap<String, String>>
. How do I bind HashMap.class
with this provider?
I looked at this but not able to figure out how to use TypeLiteral
for the HashMap
value (V) in HashMap<K,V>
. Therefore, I just replaced the V
in <K,V>
with Object. Currently my ugly binding looks like below which has obvious disadvantages. I have to get the object and cast it to HashMap<String, String>
to get further values. However this works but I am looking for a better suggestion.
binder().bind(new TypeLiteral<Map<String, Object>>() {}).toProvider(
(Class<? extends Provider<? extends Map<String, Object>>>) TestProvider.class);
Upvotes: 3
Views: 2026
Reputation: 95614
Type literals can have their generics specified two levels deep, or as deeply as you want to go. Try this.
class TestProvider implements Provider<Map<String, Map<String, String>>> {
@Override public Map<String, Map<String, String>> get() {
// If you had Guava, you could just call "return Maps.newHashMap();".
// On Java 7, you can use "return new HashMap<>();".
return new HashMap<String, Map<String, String>>();
}
}
class TestModule extends AbstractModule {
@Override protected void configure() {
bind(new TypeLiteral<Map<String, Map<String, String>>>() {})
.toProvider(TestProvider.class);
// or
bind(new TypeLiteral<HashMap<String, HashMap<String, String>>>() {})
.toProvider(HashMapTestProvider.class);
}
}
Favor interfaces instead of implementations, and note that:
HashMap<String, HashMap<String, String>>
can be cast to Map<String, HashMap<String, String>> (1)
but cannot be cast to Map<String, Map<String, String>> (2)
(1) above guarantees that it only contains HashMaps while (2) can contain any map implementation.
You may appreciate using a Guava Table
directly. It's basically a two-key map, and can create row or column maps for you as needed.
Upvotes: 3