Nested parameterized type injections

15 views
Skip to first unread message

Rodrigo Couto

unread,
Jul 22, 2008, 1:07:55 AM7/22/08
to google...@googlegroups.com
Hi, all!

I'm getting started with juice this month. I'm getting embarrassingly stuck with some issues that probably have simple solutions, but not at my reach right now.

My code base is fraught with a recurring problem: I need to inject nested parameterized types, where the type parameter of the inner injection depends on the type parameter of the outer. In order to make myself a bit clearer, I've attached a JUnit test with an example. In it,I try to inject Injected<String> to a concrete class, but Injected<T> should be also injected with a AlsoInjected<T>, where those T's are matched type parameters. Both test cases fail.

From my searches, I think there is no direct way of doing this with guice (issue 52).

Is there a recommended circumvention to this situation?

Maybe there should be a way to create a template binding on my module like:

/**
 * Denotes a type parameter variable.
 */
public static interface ANY {}

// ...

binder.bind(new TypeLiteral<AlsoInjected<ANY>>(){}).to(new TypeLiteral<AlsoInjected<ANY>>(){});

... make guice do the semi-static type checking and let type erasure do the rest :)

Cheers,

Rodrigo Couto
GuiceTest.java

limpb...@gmail.com

unread,
Jul 22, 2008, 3:29:03 AM7/22/08
to google-guice
On Jul 21, 10:07 pm, "Rodrigo Couto" <rco...@gmail.com> wrote:
> My code base is fraught with a recurring problem: I need to inject nested
> parameterized types

Today Guice has no way to inject the field
because it doesn't know what 'T' is:
@Inject private AlsoInjected<T> also;

Over the weekend I wrote some code that
moves us closer to this - we now have an API
that can reasonably resolve 'AlsoInjected<T>'
to 'AlsoInjected<String>' in your example:
http://publicobject.com/2008/07/typeresolver-tells-you-what-listget.html

The difficult part will be changing Guice so that
TypeResolver is used without breaking the
existing code that uses Guice.

Unfortunately, it seems that there's a lot of complexity
and nuance to getting this right, and I doubt we'll
have time to get it right before v 2.0, which we're
intending to release this summer.

I would definitely like this to work in one of the
follow-up releases, and it's a use case that's come
up a few times before.

As a work-around, you can create (gross) subtypes
for each injected type that makes the injected type
concrete. This will only work for constructor injection:
public static class StringInjectedImpl
extends InjectedImpl<String> {
@Inject
public StringInjectedImpl(AlsoInjected<String> alsoInjected) {
super(alsoInjected);
}
}

This solution is lame, but it should work. The other
solution is to create a factory by-hand that calls your
constructor.

Rodrigo Couto

unread,
Jul 22, 2008, 10:13:45 AM7/22/08
to google...@googlegroups.com
On Tue, Jul 22, 2008 at 4:29 AM, je...@swank.ca <limpb...@gmail.com> wrote:

Over the weekend I wrote some code that
moves us closer to this - we now have an API
that can reasonably resolve 'AlsoInjected<T>'
to 'AlsoInjected<String>' in your example:
http://publicobject.com/2008/07/typeresolver-tells-you-what-listget.html

Great news!
 
As a work-around, you can create (gross) subtypes
for each injected type that makes the injected type
concrete. This will only work for constructor injection:
 public static class StringInjectedImpl
     extends InjectedImpl<String> {
   @Inject
   public StringInjectedImpl(AlsoInjected<String> alsoInjected) {
      super(alsoInjected);
   }
 }
 
This could be more palatable if we could get CGLib or ASM to generate these sub-classes for us. I'm fighting them right now for a proof of concept for this.

(...) The other

solution is to create a factory by-hand that calls your
constructor.

... where "by-hand" you mean with no injection into the factory whatsoever, right? When I tried to inject AlsoInjected<T> on my provider (in a constructor or a field) I got myself on the same use-case as before. Playing around with example, it would need to settle for something like the following, correct?

    public static class InjectedImplProvider<T> implements
            Provider<Injected<T>> {

        private AlsoInjected<T> also;

        public InjectedImplProvider(AlsoInjected<T> also) {
            super();
            this.also = also;
        }

        @Override
        public Injected<T> get() {
            return new InjectedImpl<T>(this.also);
        }

        public static <S> InjectedImplProvider<S> forClass(Class<S> clazz) {
            return new InjectedImplProvider<S>(new AlsoInjectedImpl<S>()); //oh-ow...
        }

    }

Thanks!
Reply all
Reply to author
Forward
0 new messages