2011-12-30 61 views
2

以下通用吉斯結合方法正確行爲:我的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<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); 

任何想法如何正確創建集?

回答

2

ParameterizedType是用於表示Java源代碼中需要用尖括號寫類型的Java類:類型,如Foo<Bar>Set<Option>Set<Option<Radio>>甚至Set<? extends Option<Radio>>。這是你想要的回報價值。

你所做的事情實際上可以正確地處理你想要在倒數第二行而不是superClass.getRawType()中調用superClass.getType()的微小變化。這就是說,雖然我在這裏,我還有其他一些建議。

首先,在你的第一個方法,我想將其更改爲:

<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; 
} 

,將讓你做這樣的呼籲:如果你不使用guava

bindMultibinder(ImmutableList.of(CruiseControlSubOptOne.class, 
           CruiseControlSubOptTwo.class), 
       Option.class); 

或者, - 雖然你應該是 - 你可以使用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<?>,那麼您可能會讓該方法的調用者在嘗試使用返回值時壓制無類型的警告。最好在這裏做,在這裏你可以將警告抑制限制在一條線上,並且在那裏你可以證明演員是安全的。

+0

如果我不是獨自一人在地下室工作,我會爲您提供一個高薪的高級職位。 :)感謝您的驚人答案。自從我寫了這個問題以來,幸運的是我對泛型的理解和Guice的鍵的目的已經越來越深。我最終將添加番石榴(這是在我的雷達,我通過谷歌Gimlet間接包括它)。如果在第一次過渡到Scala之後仍然有意義,我會採用它。 – 2012-03-13 14:35:50