2012-01-23 70 views
2

我試圖帶註釋的變量注入請求範圍:吉斯:在請求範圍不能注入註釋類型

Map<Key<?>, Object> seedMap = ImmutableMap.<Key<?>, Object>builder(). 
    put(Key.get(String.class, Names.named("name")), name).build(); 
return ServletScopes.scopeRequest(new InjectingCallable<>(injector, 
    GetModule.class), seedMap).call(); 

其中,InjectingCallable注入GetModule請求範圍內:

/** 
* A Callable that is constructed in one scope and injects a Callable into a potentially separate 
* scope. 
* <p/> 
* @param <V> the type of object returned by the Callable 
* @author Gili Tzabari 
*/ 
public final class InjectingCallable<V> implements Callable<V> 
{ 
    private final Injector injector; 
    private final Class<? extends Callable<V>> delegate; 

    /** 
    * Creates a new InjectingCallable. 
    * <p/> 
    * @param injector the Guice injector 
    * @param delegate the class to inject and delegate to 
    */ 
    public InjectingCallable(Injector injector, Class<? extends Callable<V>> delegate) 
    { 
     Preconditions.checkNotNull(injector, "injector may not be null"); 
     Preconditions.checkNotNull(delegate, "delegate may not be null"); 

     this.injector = injector; 
     this.delegate = delegate; 
    } 

    @Override 
    public V call() throws Exception 
    { 
     return injector.getInstance(delegate).call(); 
    } 
} 

GetModule定義如下:

@RequestScoped 
private static class GetModule implements Callable<Module> 
{ 
    private final String name; 
    private final Session session; 

    @Inject 
    public GetModule(@Named("name") String name, Session session) 
    { 
     this.name = name; 
     this.session = session; 
    } 
} 

當我運行此代碼時,我得到這個呃ROR:

1) No implementation for java.lang.String annotated with @com.google.inject.name.Named(value=name) was bound. 
    while locating java.lang.String annotated with @com.google.inject.name.Named(value=name) 

如果我同一個變量綁定到它的工作原理全局範圍。如果我刪除註釋,它會起作用。此問題似乎特定於請求範圍註釋變量。有任何想法嗎?

+0

嘿,對於ImmutableMap的FYI,您不需要在等號右側的'builder()'調用中指定泛型,因爲您在左側具有泛型。這是靜態構建器()方法的重點。即''ImmutableMap ,Object> seedMap = ImmutableMap.builder()。put(...)。build()'。 – Tom

+1

@Tom,我得到一個編譯器錯誤,如果我這樣做。在Java7更新2下,默認情況下,它將右側解析爲。嘗試在你的最後編譯它,如果你看到相同的內容,請告訴我。 – Gili

回答

5

問題是你沒有這種類型的綁定。僅僅因爲你明確地傳播價值並不意味着你不必將其綁定。你可以說:

bind(String.class) 
    .annotatedWith(Names.named("name")) 
    .toProvider(Providers.<String>of(null)); 

,然後如果name變量的值"foo",你會得到"foo"注入,因爲你播種了。爲一個值注入一個值將它放在作用域(這只是一個緩存),以便Guice不會運行該值的提供者。通過使用null的提供者,如果它不是種子,那麼可以讓這個值炸燬。

簡而言之,Guice要求您指定一種方法來調配每個依賴項,而不管您是否打算手動播種範圍(這應該是一個相當稀有的事情)。

一些不請自來的建議: - 請避免注射進樣器。它使得更難以捕捉這些問題。最好有一個「根對象」。這是您需要撥打injector.getInstance來創建的單個對象。對於很多應用程序,這可能只是您的應用程序服務器。 (例如 - injector.getInstance(MyServer.class).startServer())。爲什麼這對你有幫助?它使得在啓動時更容易檢測到所有依賴關係都已滿足。如果您在請求期間注入注入器,並且可以調用它來創建任意對象,那麼運行時可能會因稍後的綁定而導致某些置備錯誤。此外,如果您儘早完成所有getInstance調用,編寫測試可以更輕鬆地爲您執行此操作,以便您可以簡單地運行測試以瞭解Guice綁定是否滿足。

UPDATE:

If I bind the same variable to the global scope it works.

嗯,你基本上做的我做了什麼?如果是這樣,我上面的解釋解釋了爲什麼這樣做:-)。

If I remove the annotation, it works.

這部作品的原因是因爲吉斯確實有因爲StringString綁定有一個空的構造:-)。基本上你必須有一個單一的@Inject構造函數,一個無參數構造函數或一個提供者來綁定一個類型。

+0

順便說一句,我不是說應該從不*注入注入器......但它很少用到,而且應該只用於你想爲某個人編寫一個基於guice的框架的情況爲他們提供注入事物的特殊方式。即使你這樣做,你也應該嘗試做適當的'requireBinding'調用,以免在啓動後出現意外。 – Tom

+0

我最終使用了兒童注射器(帶有私人模塊)。我發現這種方法比綁定一個從不使用的Provider更清晰。謝謝你的澄清! – Gili

+0

考慮使用引發有用的IllegalStateException的自定義提供程序(例如「@Named(\」name \「)請求範圍中未提供的字符串實例」) - 如果您犯了一個錯誤,您將得到比NullPointerException更多的幫助 –