以下通用Guice绑定方法行为正确:
<T> Key<?> bindMultibinder(
ArrayList<Class<? extends T>> contents, Class<T> superClass) {
Named annotation = randomAnnotation();
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;
}并使用如下的客户端代码:
ArrayList<Class<? extends Option>> options =
new ArrayList<Class<? extends Option>>();
options.add(CruiseControl.class);
bindMultibinder(options, Option.class);但是,如果我想允许Option接受一个像Option<Radio>这样的泛型参数,那么我假设我需要在bindMultibinder superClass参数中传递一个TypeLiteral。这是我到目前为止最好的尝试:
<T> Key<?> bindMultibinder(
ArrayList<TypeLiteral<? extends T>> contents, TypeLiteral<T> superClass) {
Named annotation = randomAnnotation();
Multibinder<T> options =
Multibinder.newSetBinder(binder(), superClass, annotation);
for (TypeLiteral<? extends T> t : contents) {
options.addBinding().to(t);
}
final Key<?> multibinderKey = Key.get(Types.setOf(superClass.getRawType()), annotation);
return multibinderKey;
}与前一种情况等效的绑定代码如下所示:
ArrayList<TypeLiteral<? extends Option>> options =
new ArrayList<TypeLiteral<? extends Option>>();
options.add(new TypeLiteral<CruiseControl>(){});
bindMultibinder(options, new TypeLiteral<Option>(){});我几乎可以肯定下面的绑定是不正确的,因为Types.setOf(superClass.getRawType())返回一个ParameterizedType
final Key<?> multibinderKey =
Key.get(Types.setOf(superClass.getRawType()), annotation);有什么办法可以正确地创建集合吗?
发布于 2012-03-13 22:28:32
ParameterizedType是一个java类,用于表示java源代码中需要用尖括号编写的类型:Foo<Bar>、Set<Option>、Set<Option<Radio>>,甚至Set<? extends Option<Radio>>这样的类型。这就是你想要的返回值。
您所做的工作实际上将正确地使用您希望在倒数第二行中调用superClass.getType()而不是superClass.getRawType()的非常小的更改。话虽如此,在这里,我确实有一些其他的建议。
首先,在您的第一种方法中,我将其更改为:
<T> Key<Set<T>> bindMultibinder(
Iterable<? extends Class<? extends T>> contents, Class<T> superClass) {
Named annotation = randomAnnotation();
Multibinder<T> options =
Multibinder.newSetBinder(binder(), superClass, annotation);
for (Class<? extends T> t : contents) {
options.addBinding().to(t);
}
@SuppressWarnings("unchecked")
final Key<Set<T>> multibinderKey = (Key<Set<T>>) Key.get(Types.setOf( superClass ), annotation);
return multibinderKey;
}它会让你像这样做调用:
bindMultibinder(ImmutableList.of(CruiseControlSubOptOne.class,
CruiseControlSubOptTwo.class),
Option.class);或者,如果您没有使用guava --尽管您应该使用--您可以使用Arrays.asList而不是ImmutableList.of。您无需在绑定代码中使用所有这些尖括号声明,即可获得与以前相同数量的类型安全。
如果bindMultibinder的调用者还不多,我也可以交换参数的顺序,但这可能只是个人风格的问题。
使用这些相同的更改,您的第二个方法将变为:
<T> Key<Set<T>> bindMultibinder(
Iterable<? extends TypeLiteral<? extends T>> contents, TypeLiteral<T> superClass) {
Named annotation = randomAnnotation();
Multibinder<T> options =
Multibinder.newSetBinder(binder(), superClass, annotation);
for (TypeLiteral<? extends T> t : contents) {
options.addBinding().to(t);
}
@SuppressWarnings("unchecked")
final Key<Set<T>> multibinderKey = (Key<Set<T>>) Key.get(Types.setOf(superClass.getType()), annotation);
return multibinderKey;
}您可以类似地使用它:
bindMultibinder(ImmutableList.of(
new TypeLiteral<CruiseControlSubOptOne>() {},
new TypeLiteral<CruiseControlSubOptTwo>() {}),
new TypeLiteral<Option>() {});虽然现在考虑了一下,但我想知道您是否真的想要使用TypeLiteral的bindMultibinder重载。难道你不想要一个接受Key的吗?
<T> Key<Set<T>> bindMultibinder(Iterable<? extends Key<? extends T>> contents, Key<T> superClass) {
Named annotation = randomAnnotation();
Multibinder<T> options =
Multibinder.newSetBinder(binder(), superClass.getTypeLiteral(), annotation);
for (Key<? extends T> t : contents) {
options.addBinding().to(t);
}
@SuppressWarnings("unchecked")
final Key<Set<T>> multibinderKey =
(Key<Set<T>>) Key.get(Types.setOf(superClass.getTypeLiteral().getType()), annotation);
return multibinderKey;
}毕竟,您可以以几乎相同的方式调用此方法:
bindMultibinder(ImmutableList.of(
new Key<CruiseControlSubOptOne>() {},
new Key<CruiseControlSubOptTwo>() {}),
new Key<Option>() {});除了Key比TypeLiteral更容易输入之外,如果您需要放入仅由其注释标识的内容,这是很容易做到的:
bindMultibinder(ImmutableList.of(
new Key<CruiseControlSubOptOne>() {},
new Key<CruiseControlSubOptTwo>() {},
Key.get(CruiseControl.class, Names.named("ThirdOpt")),
Key.get(CruiseControl.class, Names.named("FourthOpt"))),
new Key<Option>() {});现在那个@Suppress让你紧张了吗?良好的直觉。
不幸的是,不幸的是,当处理泛化类型周围的反射时-类型中有尖括号-你几乎肯定会有小的未经检查的比特。我的建议是,将需要抑制非类型化警告的部分设置得尽可能小,并尽可能多地向外界公开类型信息。如果从这里返回一个Key<?>,则很可能会使此方法的调用者在尝试使用您的返回值时抑制未键入的警告。更好的做法是在这里这样做,您可以将警告抑制限制为一行,并且可以证明强制转换是安全的。
https://stackoverflow.com/questions/8683652
复制相似问题