Need help using keys with generics and TypeLiterals

2,729 views
Skip to first unread message

glenviewjeff

unread,
Dec 29, 2011, 3:22:55 PM12/29/11
to google...@googlegroups.com
Also posted on Stack Overflow.

This code functions as expected:

ArrayList<Class<? extends Option>> options = 
 
new ArrayList<Class<? extends Option>>();
bindMultibinder
(annotation, options);

public Key<Set<Option>> bindMultibinder(
 
Named annotation, ArrayList<Class<? extends Option>> contents) {
   
Multibinder<Option> options =
   
Multibinder.newSetBinder(binder(), Option.class, annotation);
   
for (Class<? extends Option> option : contents) {
      options
.addBinding().to(option);
   
}
   
final Key<Set<Option>> multibinderKey =
   
Key.get(new TypeLiteral<Set<Option>>(){}, annotation);
   
return multibinderKey;
}

But its generic equivalent (below) does not function. Attempting to use it results in the following error:

com.google.inject.CreationException: Guice creation errors: 1) java.util.Set<T> cannot be used as a key; It is not fully specified.

Generic equivalent:

bindMultibinder(annotation, Option.class, options);

public <T> Key<Set<T>> bindMultibinder(
 
Named annotation, Class<T> superClass, ArrayList<Class<? extends T>> contents) {
   
Multibinder<T> options =
     
Multibinder.newSetBinder(binder(), superClass, annotation);
   
for (Class<? extends T> t : contents) {
      options
.addBinding().to(t);
   
}
   
final Key<Set<T>> multibinderKey =
   
Key.get(new TypeLiteral<Set<T>>(){}, annotation);
   
return multibinderKey;
}


Guice's Key documentation states only that:

Key supports generic types via subclassing just like TypeLiteral.

I need more help than that to figure out how to replace the Key<Set<T>> with something like Key<Set<TypeLiteral<T>>>

Thanks for any help!

Stuart McCulloch

unread,
Dec 29, 2011, 5:01:08 PM12/29/11
to google...@googlegroups.com
^ the new TypeLiteral<...>(){} anonymous class trick only works when the type parameter is known at compile time.

If you need to build generic types at runtime you can use the com.google.inject.util.Types utility class, for example:

    final Key<Set<T>> multibinderKey =
        Key.get( Types.setOf( superClass ), annotation );

HTH
   return multibinderKey;
}


Guice's Key documentation states only that:

Key supports generic types via subclassing just like TypeLiteral.

I need more help than that to figure out how to replace the Key<Set<T>> with something like Key<Set<TypeLiteral<T>>>

Thanks for any help!

--
You received this message because you are subscribed to the Google Groups "google-guice" group.
To view this discussion on the web visit https://groups.google.com/d/msg/google-guice/-/N7baUuZY8MsJ.
To post to this group, send email to google...@googlegroups.com.
To unsubscribe from this group, send email to google-guice...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-guice?hl=en.

glenviewjeff

unread,
Dec 29, 2011, 9:41:43 PM12/29/11
to google...@googlegroups.com
Awesome Stuart, thanks so much!  I was able to get it to execute correctly, albeit with an unchecked cast and warning as below.  Do you (or does anyone else) know of any way around this?

final Key<Set<T>> multibinderKey = (Key<Set<T>>) Key.get(Types.setOf( superClass ), annotation);

Russ Milliken

unread,
Dec 29, 2011, 9:58:40 PM12/29/11
to google...@googlegroups.com
FWIW, that's the only way I've been able to get it to work (class cast and warning).

-Russ

On Thu, Dec 29, 2011 at 9:41 PM, glenviewjeff <glenvi...@gmail.com> wrote:
Awesome Stuart, thanks so much!  I was able to get it to execute correctly, albeit with an unchecked cast and warning as below.  Do you (or does anyone else) know of any way around this?

final Key<Set<T>> multibinderKey = (Key<Set<T>>) Key.get(Types.setOf( superClass ), annotation);

--
You received this message because you are subscribed to the Google Groups "google-guice" group.
To view this discussion on the web visit https://groups.google.com/d/msg/google-guice/-/qYnPiVt-cqoJ.

Stuart McCulloch

unread,
Dec 30, 2011, 5:59:21 AM12/30/11
to google...@googlegroups.com
On 30 Dec 2011, at 02:58, Russ Milliken wrote:
FWIW, that's the only way I've been able to get it to work (class cast and warning).

Yep, I forgot to add the cast - the reason you need it is because this approach uses:

   Key<?> Key.get(Type type, Annotation annotation)

and the compiler can't infer the Key's type argument from the raw "java.lang.reflect.Type" instance (it has no generic signature).

It's the opposite of the usual erasure problem - here the generic parameters are available at runtime, but not at compile time :)

glenviewjeff

unread,
Dec 30, 2011, 9:23:41 AM12/30/11
to google...@googlegroups.com
Thanks very much Stuart for the help.  I was able to remove the unchecked cast and maintain correct operation by modifying the code as follows:

   public <T> Key<?> bindMultibinder(Named annotation, Class<T> superClass, ArrayList<Class<? extends T>> contents) {

      Multibinder<T> options = Multibinder.newSetBinder(binder(), superClass, annotation);
      for (Class<? extends T> t : contents) {
         options.addBinding().to(t);
      }
      final Key<?> multibinderKey = Key.get(Types.setOf( superClass ), annotation);
      return multibinderKey;
   }

Reply all
Reply to author
Forward
0 new messages