Injecting generic objects

25 views
Skip to first unread message

Matt G

unread,
Dec 27, 2008, 8:40:39 PM12/27/08
to google-guice
Hi,

Is it possible to inject a generic object as the below code sample
attempts to do? The below code compiles but throws an error see below
for stack.

I've tried to search the discussion boards regarding this issue, and
while it seems it is not possible in Guice 1.0, it is indicated in
http://publicobject.com/2008/11/guice-punches-erasure-in-face.html,
that this is possible in Guice 2.0.

I'm extremely new to Guice, so it's entirely possible I have missed
something fundamental. Any help would be greatly appreciated.


Matt G.

[java]
class Foo<T> {
private final Bar<T> bar;

@Inject
Foo(Bar<T> bar) {
this.bar = bar;
}

public Bar<T> getBar() {
return bar;
}

public static void main(String[] args) {
Injector injector = Guice.createInjector(new MyModule());
Foo<String> stringFoo = injector.getInstance(new
Key<Foo<String>>() {});
System.out.println(stringFoo.getBar().getValue());
}
}


class Bar<T> {
private final T t;

@Inject
Bar(T t) {
this.t = t;
}

public T getValue() {
return t;
}
}

class MyModule extends AbstractModule {

protected void configure() {
bind(String.class).toInstance("Hello");
}
}
[\java]
/System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Home/bin/
java -Dfile.encoding=MacRoman -classpath /System/Library/Frameworks/
JavaVM.framework/Versions/1.5.0/Home/lib/deploy.jar:/System/Library/
Frameworks/JavaVM.framework/Versions/1.5.0/Home/lib/dt.jar:/System/
Library/Frameworks/JavaVM.framework/Versions/1.5.0/Home/lib/
javaws.jar:/System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/
Home/lib/jce.jar:/System/Library/Frameworks/JavaVM.framework/Versions/
1.5.0/Home/lib/plugin.jar:/System/Library/Frameworks/JavaVM.framework/
Versions/1.5.0/Home/lib/sa-jdi.jar:/System/Library/Frameworks/
JavaVM.framework/Versions/1.5.0/Home/../Classes/charsets.jar:/System/
Library/Frameworks/JavaVM.framework/Versions/1.5.0/Home/../Classes/
classes.jar:/System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/
Home/../Classes/dt.jar:/System/Library/Frameworks/JavaVM.framework/
Versions/1.5.0/Home/../Classes/jce.jar:/System/Library/Frameworks/
JavaVM.framework/Versions/1.5.0/Home/../Classes/jconsole.jar:/System/
Library/Frameworks/JavaVM.framework/Versions/1.5.0/Home/../Classes/
jsse.jar:/System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/
Home/../Classes/laf.jar:/System/Library/Frameworks/JavaVM.framework/
Versions/1.5.0/Home/../Classes/ui.jar:/System/Library/Frameworks/
JavaVM.framework/Versions/1.5.0/Home/lib/ext/apple_provider.jar:/
System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Home/lib/ext/
dnsns.jar:/System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/
Home/lib/ext/localedata.jar:/System/Library/Frameworks/
JavaVM.framework/Versions/1.5.0/Home/lib/ext/sunjce_provider.jar:/
System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Home/lib/ext/
sunpkcs11.jar:/Users/matt/IdeaProjects/GuiceExample/out/production/
GuiceExample:/Users/matt/Downloads/guice-snapshot20081123/guice-
snapshot20081123.jar genericinjection.Foo
Exception in thread "main" java.lang.NoClassDefFoundError: [Lorg/
aopalliance/intercept/MethodInterceptor;
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2395)
at java.lang.Class.getDeclaredMethods(Class.java:1763)
at com.google.inject.internal.ProviderMethodsModule.getProviderMethods
(ProviderMethodsModule.java:94)
at com.google.inject.internal.ProviderMethodsModule.configure
(ProviderMethodsModule.java:86)
at com.google.inject.spi.Elements$RecordingBinder.install
(Elements.java:160)
at com.google.inject.spi.Elements$RecordingBinder.install
(Elements.java:169)
at com.google.inject.spi.Elements.getElements(Elements.java:94)
at com.google.inject.InjectorBuilder.buildStatically
(InjectorBuilder.java:120)
at com.google.inject.InjectorBuilder.build(InjectorBuilder.java:97)
at com.google.inject.Guice.createInjector(Guice.java:92)
at com.google.inject.Guice.createInjector(Guice.java:69)
at com.google.inject.Guice.createInjector(Guice.java:59)
at genericinjection.Foo.main(Foo.java:23)

Process finished with exit code 1

Chandra

unread,
Dec 28, 2008, 5:24:05 AM12/28/08
to google-guice
Matt,
Pretty close. Try this.

Foo<String> stringFoo = injector.getInstance(Key.get(new
TypeLiteral<Foo<String>>(){}));

Keep in mind that generics are not reified. TypeLiterals are a way of
passing types at runtime.


On Dec 27, 5:40 pm, Matt G <matthew.gret...@gmail.com> wrote:
> Hi,
>
> Is it possible to inject a generic object as the below code sample
> attempts to do? The below code compiles but throws an error see below
> for stack.
>
> I've tried to search the discussion boards regarding this issue, and
> while it seems it is not possible in Guice 1.0, it is indicated inhttp://publicobject.com/2008/11/guice-punches-erasure-in-face.html,

Matt G

unread,
Dec 28, 2008, 5:38:39 AM12/28/08
to google-guice
Chandra,

Thank you very much for the reply. I was just about to post a follow
up myself.

The error I mentioned was in fact, due to my not including all the
necessary jars on the class path, specifically the AllianceAOP jar.

My original code did work when I had everything I needed on the
classpath.

So,

Foo<String> stringFoo = injector.getInstance(new Key<Foo<String>>()
{});
or
Foo<String> stringFoo = injector.getInstance(Key.get(new
TypeLiteral<Foo<String>>(){}));

will work.

Sorry to have wasted your time. Still, I very much appreciate you
taking the time to reply to my post.

Thanks,

Matt.

Leigh Klotz

unread,
Jan 9, 2009, 7:30:26 PM1/9/09
to google-guice
Here's a use case, done without using injectors directly, so it's a
little more of a worked-up example:

Consider the interface Foo:

public interface Foo<T> {
Collection<T> get();
}

A natural implementation of Foo (albeit a trivial one that always
provides an empty Collection) would be the following:

public class FooImpl<T> implements Foo<T> {
public Collection<T> get() {
return Collections.emptyList();
}
}

How do we tell Guice to that we want a different FooImpl for each Foo
concrete parameterized type?

It turns out to not to be possible without enumerating the
parameterized class types, which makes sense, since each Guice bind()
expresses one binding.

So, let's acknowledge this explicitly by making FooImpl a little more
life-like, as as Singleton returning some particular Collection:

public interface Foo<T> {
void add(T t);
Collection<T> get();
}

@Singleton
public class FooImpl<T> implements Foo<T> {
private final List<T> list = new LinkedList<T>();
@Inject FooImpl<T>() { }
public void add(T t) { list.add(T); }
public Collection<T> get() {
return list;
}
}

Now it becomes clearer that there must be a Singleton FooImpl instance
for each T, and hence a binding for each T.

In Java 5 (and 6), generics are "erased" at the end of compilation, so
there is no run-time record of the types, and so the paramaterization
is unavailable to Java reflection. Guice uses instances of concrete
subclasses of a paramaterized, abstract class called TypedLiteral to
represent paramaterized generic types. Bindings may be expressed not
only in Java types, but also in TypeLiteral (subclass) instances,
which provide type reflection for parameterized generics:

public class FooModule extends AbstractModule {
public void configure() {
bind(new TypeLiteral<Foo<String>>(){}).to(new
TypeLiteral<FooImpl<String>>(){});
bind(new TypeLiteral<Foo<Integer>>(){}).to(new
TypeLiteral<FooImpl<Integer>>(){});
}
}

Eric Anderson

unread,
Jan 12, 2009, 9:31:49 AM1/12/09
to google...@googlegroups.com
Leigh,

Looks like the makings of a good blog post...

Eric

Leigh Klotz

unread,
Jan 14, 2009, 4:42:08 PM1/14/09
to google-guice
Thank you for the compliment. If the guicier folks here think it's
correct, that's great! I'd prefer to contribute it to the wiki though
after it's been vetted.

Andreas Petersson

unread,
Jan 22, 2009, 3:42:33 AM1/22/09
to google...@googlegroups.com
thanks for that hint. i have created an implementation for each
GenericDao<T> very non-DRY .
your approach might work, i'll try that out.
Reply all
Reply to author
Forward
0 new messages