给出此方法签名,可以实现它吗?如果可以,怎么办?
TypeLiteral<MyClass<T, R>> combineTypes(Class<T> typeOne, Class<R> typeTwo) {
// Awesome implementation here
}
背景
我有一个接口ApiHandler<TReq, TRes>
,我正在尝试在工厂中使用给定类型TReq
的Guice创建该接口。如有必要,我还可以传递类型TRes
。不幸的是,TReq
和TRes
没有有意义的父类或接口,原因超出了我的控制范围(它们是从Apache Thrift生成的)。
答案 0 :(得分:3)
如果您基于运行时参数进行计算,则不再是 literal :它只是类型。
尽管您可以使用Guava的TypeToken等效框架及其实用程序,但Guice内置了一个Type实用程序类:com.google.inject.util.Types。使用newParameterizedType(Type rawType, Type... typeArguments)
创建所需的类型,注意ParameterizedType和Class都实现Type。
static ParameterizedType combineTypes(Class<?> typeOne, Class<?> typeTwo) {
return Types.newParameterizedType(MyClass.class, typeOne, typeTwo);
}
不幸的是,AbstractModule.bind
和LinkedBindingBuilder.to
没有为Type提供重载;只是Class,TypeLiteral和Key。幸运的是,您可以使用Key.get(Type)
使用Type反射地生成Key:
bind(Key.get(combineTypes(Foo.class, Bar.class))).to(MyClassFooBar.class);
请注意,在此,ParameterizedType本身不是参数化类型。这使Guice的bind
EDSL提供了一些巧妙的基于泛型的保护。要使以上功能正常工作,您可能需要@SuppressWarnings
,返回原始类型Key
或考虑让combineTypes
返回Key<MyClass<T, R>>
(这需要从{进行强制转换{1}}的返回值Key.get(Type)
)。如果确实必须使用TypeLiteral,则可以通过Key.getTypeLiteral生成TypeLiteral,但这也需要从Key<?>
进行强制类型转换-并且在任何有意义的定义下都不会是“类型文字”。>
答案 1 :(得分:1)
TypeLiteral
有两个构造函数。正常使用的TypeLiteral<MyClass<Foo, Bar>>() {}
,不安全的不是通用的,而是直接创建的:new TypeLiteral(type)
。查看Guice的TypeLiteral here的代码,我们看到常规构造函数对此参数使用parameterized.getActualTypeArguments()[0]
,其中parameterized
是ParameterizedType
。为了制作与MyClass<R, T>
相匹配的内容,这将是另一个ParameterizedType
,但具有两个参数(而不是一个),每个参数将是一个普通类。现在,您可以创建一个ParameterizedType
接口的实现,以实现所需的合同,构造一个TypeLiteral
并将其强制转换为正确的返回值(它将没有正确的泛型类型,您将必须进行不安全的投射)。
它看起来像这样:
TypeLiteral<MyClass<T, R>> combineTypes(Class<T> typeOne, Class<R> typeTwo) {
return new TypeLiteral(new ParameterizedType() {
@RecentlyNonNull
Type[] getActualTypeArguments() {
return new Type[] {typeOne, typeTwo};
}
@RecentlyNonNull
Type getRawType() {
return MyClass.class;
}
Type getOwnerType() {
// this is only needed for nested classes, eg. if this was Foo.Myclass this would return Foo.class.
return null;
}
});
}
答案 2 :(得分:-1)
我以前没有使用过Guice或Thrift,希望对您有所帮助。
MyClass的定义:public class MyClass<T, R> {}
通过添加类型参数来实现该方法:
public static <T, R> TypeLiteral<MyClass<T, R>> combineTypes(Class<T> typeOne, Class<R> typeTwo) {
return new TypeLiteral<MyClass<T, R>>() {};
}
public static void main(String[] args) {
TypeLiteral<MyClass<Integer, String>> myClassTypeLiteral = TypeTest.combineTypes(Integer.class, String.class);
}
或者简单地:
public static <T, R> TypeLiteral<MyClass<T, R>> combineTypes() {
return new TypeLiteral<MyClass<T, R>>() {};
}
public static void main(String[] args) {
TypeLiteral<MyClass<Integer, String>> myClassTypeLiteral = TypeTest.<Integer, String>combineTypes();
}