以下通用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>
这样的通用参数,那么我假设我需要在TypeLiteral
superClass参数中传递bindMultibinder
。到目前为止,这是我最好的尝试:
<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);
有关如何正确创建设置的任何想法吗?
答案 0 :(得分:2)
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>() {});
虽然现在正在思考,但我想知道你是否真的想要bindMultibinder
的重载需要TypeLiteral
。你宁愿选择一个需要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<?>
,那么当您尝试使用返回值时,您可能会使此方法的调用者禁止无类型警告。最好在这里做,你可以将警告抑制限制在一行,并且你可以证明演员是安全的。