Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Guice: how do I bind generics for ALL types?

Tags:

java

guice

Suppose I have the following pattern repeating often in my code:

class A<T> {
    @Inject
    public A(List<T> list) {
        // code
    }
}

I want to bind all List<T> to ArrayList<T>. I know I can use TypeLiterals to bind an explicit raw type, e.g., List<String>, but is there anyway to do this for all types?

Basically, this code should not fail because I didn't bind List explicitly:

injector.getInstance(new Key<A<Integer>>(){});
like image 427
Gal Avatar asked Apr 16 '15 13:04

Gal


1 Answers

This is not possible in Guice. Internally Guice is little more than a HashMap<Key, Provider<?>>, where a Key represents an optional binding annotation and a single fully-qualified type. To match a "pattern" of types would require a Key to behave more like a predicate, which would require a very different architecture and which would make binding lookup much slower.

Furthermore, though you may be using List for a simple example, remember that Guice bindings are better reserved for equivalent implementations that are likely to vary in production or tests. In addition to having very different algorithm-specific performance characteristics, List implementations vary in their ability to handle null items, and once you've picked an ideal list implementation for a given algorithm you're unlikely to need to change it—especially in an application-wide configuration.

If you do want to be able to vary your generic implementations with Guice-style configuration, create a very small factory like ListFactory:

public class ListFactory {
  public <T> List<T> createFooBarList() { return new ArrayList<T>(); }
  public <T> List<T> createSomeOtherList() { return new LinkedList<T>(); }
}
like image 192
Jeff Bowman Avatar answered Oct 03 '22 16:10

Jeff Bowman