views:

63

answers:

3

I have an interface Producer<T> and a concrete FooProducer that implements Producer<Foo>. Binding this in guice looks ugly as sin:

bind(new TypeLiteral<Producer<Foo>>() {}).to(FooProducer.class);

I have lots of these such bindings. I have tried the following:

static <T> TypeLiteral<Producer<T>> producer() {
    return new TypeLiteral<Producer<T>>(){};
}

With calls made in this way:

bind(ContainingClass.<Foo>producer()).to(FooProducer.class);

But it gives an error along the lines of Producer<T> is not specific enough....

Am I going about this in the wrong way?

+2  A: 

I believe that due to how TypeLiterals work, you have to actually write new TypeLiteral<Producer<Foo>>(){} or the necessary type information will not be available. They utilize the fact that a class that has fully specified its generic types can have information on those types retrieved. When you write new TypeLiteral<Producer<T>>(){}, you aren't specifying what T is, so that information isn't available.

It's subjective, but I don't think creating a type literal looks too ugly, considering what it does.

As an aside, I don't know what your Producer interface does, but if it is just used for producing instances of T (with a method that takes no arguments), you could use Guice's Provider interface instead. Then you just have to do:

bind(Foo.class).toProvider(FooProvider.class);

And you can inject a Foo or a Provider<Foo> anywhere.

ColinD
That's quite interesting I hadn't thought about it that way. My `Producer` interface does a number of other things also, but I will keep this approach in mind for the future. Thanks.
Finbarr
The `@Provides` method that Jesse mentions in his answer is equivalent to writing a custom `Provider` implementation as well, and a lot easier.
ColinD
+3  A: 

You can save 8 characters by typing new Key<Producer<Foo>>(){} rather than new TypeLiteral<Producer<Foo>>(){}. Or by using the equivalent @Provides method:

@Provides
public Producer<Foo> provideFooProducer(FooProducer fooProducer) {
  return fooProducer;
}
Jesse Wilson
+3  A: 

Instead of

bind(new TypeLiteral<Producer<Foo>>() {}).to(FooProducer.class);

try a convenience method like

static <T> Key<Producer<T>> producerOf(Class<T> type) {
  return (Key<Producer<T>>)Key.get(Types.newParameterizedType(Producer.class,type));
}

and then in your module

bind(producerOf(Foo.class)).to(FooProducer.class);

That unchecked cast should be safe. Key is com.google.inject.Key and Types is com.google.inject.util.Types.

good luck

Darren Gilroy
This works in this simple case but doesn't if you want, say, `Producer<List<Foo>>`. Overall it seems like a waste of effort, especially when you have to make a method like this for every parameterized type you want to use, but whatever floats the OP's boat I guess.
ColinD