首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >这个泛型Guice绑定方法的TypeLiteral等效项有什么问题?

这个泛型Guice绑定方法的TypeLiteral等效项有什么问题?
EN

Stack Overflow用户
提问于 2011-12-31 04:16:31
回答 1查看 1.2K关注 0票数 2

以下通用Guice绑定方法行为正确:

代码语言:javascript
复制
<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;
}

并使用如下的客户端代码:

代码语言:javascript
复制
ArrayList<Class<? extends Option>> options = 
 new ArrayList<Class<? extends Option>>();
options.add(CruiseControl.class);
bindMultibinder(options, Option.class);

但是,如果我想允许Option接受一个像Option<Radio>这样的泛型参数,那么我假设我需要在bindMultibinder superClass参数中传递一个TypeLiteral。这是我到目前为止最好的尝试:

代码语言:javascript
复制
<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;
}

与前一种情况等效的绑定代码如下所示:

代码语言:javascript
复制
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

代码语言:javascript
复制
final Key<?> multibinderKey = 
 Key.get(Types.setOf(superClass.getRawType()), annotation);

有什么办法可以正确地创建集合吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-03-13 22:28:32

ParameterizedType是一个java类,用于表示java源代码中需要用尖括号编写的类型:Foo<Bar>Set<Option>Set<Option<Radio>>,甚至Set<? extends Option<Radio>>这样的类型。这就是你想要的返回值。

您所做的工作实际上将正确地使用您希望在倒数第二行中调用superClass.getType()而不是superClass.getRawType()的非常小的更改。话虽如此,在这里,我确实有一些其他的建议。

首先,在您的第一种方法中,我将其更改为:

代码语言:javascript
复制
<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;
}

它会让你像这样做调用:

代码语言:javascript
复制
bindMultibinder(ImmutableList.of(CruiseControlSubOptOne.class,
                                 CruiseControlSubOptTwo.class),
                Option.class);

或者,如果您没有使用guava --尽管您应该使用--您可以使用Arrays.asList而不是ImmutableList.of。您无需在绑定代码中使用所有这些尖括号声明,即可获得与以前相同数量的类型安全。

如果bindMultibinder的调用者还不多,我也可以交换参数的顺序,但这可能只是个人风格的问题。

使用这些相同的更改,您的第二个方法将变为:

代码语言:javascript
复制
<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;
}

您可以类似地使用它:

代码语言:javascript
复制
bindMultibinder(ImmutableList.of(
                    new TypeLiteral<CruiseControlSubOptOne>() {},
                    new TypeLiteral<CruiseControlSubOptTwo>() {}),
                new TypeLiteral<Option>() {});

虽然现在考虑了一下,但我想知道您是否真的想要使用TypeLiteralbindMultibinder重载。难道你不想要一个接受Key的吗?

代码语言:javascript
复制
<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;
}

毕竟,您可以以几乎相同的方式调用此方法:

代码语言:javascript
复制
bindMultibinder(ImmutableList.of(
                    new Key<CruiseControlSubOptOne>() {},
                    new Key<CruiseControlSubOptTwo>() {}),
                new Key<Option>() {});

除了KeyTypeLiteral更容易输入之外,如果您需要放入仅由其注释标识的内容,这是很容易做到的:

代码语言:javascript
复制
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<?>,则很可能会使此方法的调用者在尝试使用您的返回值时抑制未键入的警告。更好的做法是在这里这样做,您可以将警告抑制限制为一行,并且可以证明强制转换是安全的。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8683652

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档