我的这个通用 Guice 绑定方法的 TypeLiteral 等价物有什么问题?
以下通用 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
这样的通用参数,那么我假设我需要在 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);
您有如何正确创建集合的想法吗?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
ParameterizedType
是一个 java 类,用于表示在 java 源代码中需要用尖括号编写的类型:例如Foo
或Set<; 等类型。 Option>
或Set
甚至Set>
。这就是你想要的返回值。事实上,您所做的工作只需在倒数第二行中调用
superClass.getType()
而不是superClass.getRawType() 的微小更改即可正常工作
。话虽这么说,当我在这里时,我确实有一些其他建议。首先,在您的第一种方法中,我将其更改为:
这将让您执行如下调用:
或者,如果您不使用 guava - 虽然你应该这样做 - 你可以使用
Arrays.asList
而不是ImmutableList.of
。您可以获得与以前相同的类型安全性,而无需在绑定代码中使用所有这些尖括号声明。如果您还没有很多
bindMultibinder
调用者,我也会交换参数的顺序,但这可能只是个人风格的问题。通过这些相同的更改,您的第二种方法将变为:
您可以类似地使用它:
虽然现在考虑一下,我想知道您是否真的想要一个采用
TypeLiteral
的bindMultibinder
重载>。您不想拥有一个需要Key
的设备吗?毕竟,您可以以几乎相同的方式调用此方法:
除了
Key
比TypeLiteral
更容易键入,并且如果您需要放入仅由它的注释,这很简单:现在,@Suppress 是否让您感到紧张?良好的直觉。
不幸的是,可悲的事实是,当处理泛型类型(其中带有尖括号的类型)的反射时,您几乎肯定会有小的未经检查的位。我的建议是,将需要抑制非类型化警告的部分做得尽可能小,并向外界公开尽可能多的类型信息。如果您从此处返回
Key
,您可能会让此方法的调用者在尝试使用您的返回值时抑制非类型化警告。最好在这里执行此操作,您可以将警告抑制限制为一行,并且可以证明强制转换是安全的。ParameterizedType
is the java class that is used to represent types that in java source code you need to write with angle brackets: types likeFoo<Bar>
orSet<Option>
orSet<Option<Radio>>
or evenSet<? extends Option<Radio>>
. That is the return value you want.What you've done will in fact work correctly with the very minor change that you want to call
superClass.getType()
in your next-to-last line instead ofsuperClass.getRawType()
. That being said, while I'm here I do have a few other suggestions.First off, in your first method I'd change it to:
That will let you do calls like this:
Or, if you aren't using guava - though you should be - you can use
Arrays.asList
instead ofImmutableList.of
. You get the same amount of type safety as before without needing all those angle bracket declarations in your binding code.If you don't have many callers of
bindMultibinder
yet, I'd also swap the order of the arguments, but that might just be a personal style thing.With these same changes, your second method becomes:
And you can use it similarly:
Though thinking about it now, I wonder if you really want an overload of
bindMultibinder
that takes aTypeLiteral
. Wouldn't you rather have one that takes aKey
instead?After all, you can call this method in almost the same fashion:
Except that
Key
is easier to type thanTypeLiteral
, and if you need to put in something that's identified only by its annotation, that's trivial to do:Now, is that
@Suppress
making you nervous? Good instincts.Unfortunately, the sad fact is that when dealing with reflection around generified types - types with angle brackets in them - you're almost certainly going to have small unchecked bits. My suggestion is that you make the bit that needs to have untyped warnings suppressed as small as possible, and expose to the outside world as much type information as you can. If you return a
Key<?>
from here, you're likely going to make the caller of this method suppress untyped warnings when they try to use your return value. Better to do it here, where you can limit the warnings suppression to a single line, and one where you can prove that the cast is safe.