Is it possible to combine two types to create another TypeLiteral?
Given this method signature, is it possible to implement it? If yes, what to do?
TypeLiteral<MyClass<T, R>> combineTypes(Class<T> typeOne, Class<R> typeTwo) {
Awesome implementation here
}
Background
I
have an interface, ApiHandler<TReq, TRes> I’m trying to use Guice to create in a factory, given type
TReq
. Unfortunately,
TReq
and TRes
don’t have meaningful parent classes or interfaces for reasons beyond my control (they are generated from Apache Thrift).
Solution
If you evaluate it based on runtime parameters, it is no longer literal: it is just a type.
While you can use Guava’s equivalent TypeToken framework and its utilities, there is a Type utility class built into Guice: com.google.inject.util.types newParameterizedType(Type rawType, Type... typeArguments)
to create the type you want, noting that both ParameterizedType and Class implement types.
static ParameterizedType combineTypes(Class<?> typeOne, Class<?> typeTwo) {
return Types.newParameterizedType(MyClass.class, typeOne, typeTwo);
}
Unfortunately, AbstractModule.bin
and LinkedBindingBuilder.to
do not provide overloads for types; Only Class, TypeLiteral, and Key. Fortunately, you can use type reflection to generate keys, using Key.get (Type)
:
bind(Key.get(combineTypes(Foo.class, Bar.class))).to(MyClassFooBar.class);
Note that the ParameterizedType itself is not a parameterized type here. This breaks some of Guice’s ingenious generic-based protection bind
EDSL offers. For the above to work, you may need to @SuppressWarnings
, return the primitive type Key, or consider having combineTypes
return Key<MyClass<T, R>>
(this needs to be done from Key.get
(Type)
The return value of Key<?>
is converted). If you really have to use TypeLiteral, you can do it Key.getTypeLiteral Generate a TypeLiteral. , but this also requires type conversion from TypeLiteral<?>
—and won’t be any meaningful definition of “type literal”.