Binding a parameterized type

56 views
Skip to first unread message

Trent Bowman

unread,
Oct 20, 2008, 4:51:37 PM10/20/08
to google-guice
Maybe this has been answered before, but I wasn't able to find it in
the archives. Or, maybe it is in the Guice book, but mine is still in
the ordering process...

Here's the class I want to inject dependencies into:

public class ProcessorImpl<T> implements Processor<T>
{
private final Subprocessor<T> subprocessor;

@Inject
public ProcessorImpl(Subprocessor<T> subprocessor)
{
super();
this.subprocessor = subprocessor;
}

public T process(List<T> list)
{
...
}
}

The constructor wants a Subprocessor<T>. However, I cannot figure out
how (or if it is possible) to bind a parameterized type. The best I've
come up with is this module:

public static class MyModule implements Module
{
public void configure(final Binder binder)
{
binder.bind(new TypeLiteral<Processor<String>>(){}).to(new
TypeLiteral<ProcessorImpl<String>>(){});
binder.bind(new TypeLiteral<Subprocessor<String>>()
{}).to(new TypeLiteral<StringConcater>(){});
}
}

and then this main() method:

public static void main(final String[] argv)
{
final Injector injector = Guice.createInjector(new
MyModule());
injector.getInstance(Key.get(new
TypeLiteral<Processor<String>>(){}));
}

My thoughts here were that, by asking guice for a Processor<String>
(which is bound to ProcessorImpl<String>), the T is now the concrete
type String, so guice should be looking for a binding for
Subprocessor<String>. But, I get this error:

1) Error at
example07_generics.ProcessorImpl.<init>(ProcessorImpl.java:15):
Binding to example07_generics.Subprocessor<T> not found. No bindings
to that type were found.

And now I'm stuck, because I can't create a TypeLiteral with
parameterized types, only concrete ones. I can work around the problem
with another Gafter-ish trick and make a little shim class of concrete
type:

public class ProcessorStringImpl extends ProcessorImpl<String>
{
@Inject
public ProcessorStringImpl(final Subprocessor<String>
subprocessor)
{
super(subprocessor);
}

}

and then tweaking the module a bit:

public static class MyModule implements Module
{
public void configure(final Binder binder)
{
binder.bind(new TypeLiteral<Processor<String>>(){}).to(new
TypeLiteral<ProcessorStringImpl>(){});
binder.bind(new TypeLiteral<Subprocessor<String>>()
{}).to(new TypeLiteral<StringConcater>(){});
}
}

Is this the best way to work around the issue? If so, can it be added
to the recipes page?

Robbie Vanbrabant

unread,
Oct 20, 2008, 5:48:17 PM10/20/08
to google...@googlegroups.com
Guice 2.0 has some improvements in this area, for example TypeResolver: http://publicobject.com/2008/07/typeresolver-tells-you-what-listget.html
It seems to be possible to solve this problem properly, so I suggest you open an issue in the tracker for your problem to make sure it gets addressed.

Now, for a temporary solution, your intermediate class could actually be a ProcessorProvider, which feels a little bit more natural. Or if you're willing to use a Guice 2.0 snapshot, I highly recommend provider methods:


  static class MyModule implements Module {
    public void configure(final Binder binder) {
      binder.bind(new TypeLiteral<Subprocessor<String>>(){}).to(StringConcater.class);
    }
   
    @Provides
    public Processor<String> getProcessor(Subprocessor<String> subProcessor) {
      return new ProcessorImpl<String>(subProcessor);
    }
  }

Hope this helps,
Robbie

limpb...@gmail.com

unread,
Oct 21, 2008, 1:20:58 AM10/21/08
to google-guice


On Oct 20, 2:48 pm, "Robbie Vanbrabant" <robbie.vanbrab...@gmail.com>
wrote:
> Guice 2.0 has some improvements in this area, for example TypeResolver:http://publicobject.com/2008/07/typeresolver-tells-you-what-listget.html
> It seems to be possible to solve this problem properly, so I suggest you
> open an issue in the tracker for your problem to make sure it gets
> addressed.

Yup, Robbie's nailed it. We're going to change Guice
so you can use type variables in injection points, like so:
@Inject List<T> injectTees;

This isn't implemented yet, but when it's ready it'll
solve this problem cleanly. For now, the only workaround
is to create distinct subclasses or provider methods for
each distinct T.

tzwoenn

unread,
Oct 21, 2008, 8:03:56 AM10/21/08
to google-guice
Can we get some feedback, when this is implemented in the trunk? I am
also interested in having this feature.

BR, Sven

limpb...@gmail.com

unread,
Nov 5, 2008, 3:35:13 AM11/5/08
to google-guice
On Oct 21, 4:03 am, tzwoenn <sven.linsta...@googlemail.com> wrote:
> Can we get some feedback, when this is implemented in the trunk? I am
> also interested in having this feature.

FYI, this feature was checked in yesterday. If you have code like
this:
public class ProcessorImpl<T> implements Processor<T> {
@Inject Subprocessor<T> subprocessor;
...
}
...when you make the following bindings, Guice will do the right thing
and inject the string subprocessor.
public void configure() {
bind(new TypeLiteral<Processor<String>>() {})
.to(new TypeLiteral<ProcessorImpl<String>>() {});
bind(new TypeLiteral<Subprocessor<String>>() {}).to(...)

I'm curious - do you have concrete examples of what you're using it
for? I'm looking for something interesting to put into the
documentation...

Dhanji R. Prasanna

unread,
Nov 5, 2008, 5:37:41 AM11/5/08
to google...@googlegroups.com
Daos are the best use case for this.

Rahul

unread,
Nov 7, 2008, 3:05:04 AM11/7/08
to google-guice
Hi,

I built a snapshot from rev 661 and using it in one of my Stripes
based web-app. I haven't looked closely but I am seeing the following
error:

Nov 7, 2008 9:02:14 PM net.sourceforge.stripes.util.Log error
SEVERE:
java.lang.NullPointerException
at com.google.inject.InjectorImpl.injectMembers(InjectorImpl.java:
690)
at
com.googlecode.stripesguicer.StripesFakeFilterChain.doFilter(StripesFakeFilterChain.java:
42)
at com.google.inject.servlet.GuiceFilter.doFilter(GuiceFilter.java:
46)
at
com.googlecode.stripesguicer.GuiceInterceptor.intercept(GuiceInterceptor.java:
73)
at
net.sourceforge.stripes.controller.ExecutionContext.proceed(ExecutionContext.java:
155)
at
net.sourceforge.stripes.controller.BeforeAfterMethodInterceptor.intercept(BeforeAfterMethodInterceptor.java:
113)
at
net.sourceforge.stripes.controller.ExecutionContext.proceed(ExecutionContext.java:
155)
at
net.sourceforge.stripes.controller.ExecutionContext.wrap(ExecutionContext.java:
74)
at
net.sourceforge.stripes.controller.DispatcherServlet.requestComplete(DispatcherServlet.java:
223)
at
net.sourceforge.stripes.controller.DispatcherServlet.service(DispatcherServlet.java:
197)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:
290)
at
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:
206)
at
net.sourceforge.stripes.controller.StripesFilter.doFilter(StripesFilter.java:
247)
at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:
235)
at
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:
206)
at
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:
233)
at
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:
175)
at
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:
128)
at
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:
102)
at
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:
109)
at
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:
286)
at
org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:
844)
at org.apache.coyote.http11.Http11Protocol
$Http11ConnectionHandler.process(Http11Protocol.java:583)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:
447)
at java.lang.Thread.run(Thread.java:619)


I can confirm that this was working with a snapshot built off rev
649.

Happy to provide any other info if required.

Cheers,
Rahul

limpb...@gmail.com

unread,
Nov 7, 2008, 3:27:13 AM11/7/08
to google-guice
On Nov 7, 12:05 am, Rahul <rahul.thakur.x...@gmail.com> wrote:
> SEVERE:
> java.lang.NullPointerException
> at com.google.inject.InjectorImpl.injectMembers(InjectorImpl.java:
> 690)

It's working as intended - you can't injectMembers() on a null.

Reply all
Reply to author
Forward
0 new messages