2017-01-21 22 views
0

當我嘗試在枚舉中注入Logger生產者時,我得到了一個N​​PE。我怎樣才能在一個枚舉中注入一個記錄器?如何在枚舉中注入記錄器

例子:

public enum MyEnum { 

    HI("Hi there!"), 
    HELLO("Hello mister!"); 

    @Inject 
    private Logger log; 

    private final String greeting; 

    private MyEnum(String greeting) { 
     this.greeting = greeting; 
//  this.log = LoggerFactory.getLogger(this.getClass()); 
    } 

    public String getGreeting() { 
     log.debug("Method getGreeting called"); 
     return this.greeting; 
    } 

} 

該類給我的log.debug()線NPE。當我刪除@Inject並取消註釋this.log行它的作品。

測試用例看起來是這樣的:

對於這個問題
@RunWith(Arquillian.class) 
public class CoverKindTest { 

    @Deployment 
    public static WebArchive createDeployment() { 
     return ShrinkWrap.create(WebArchive.class, "test.war") 
       .addClass(MyEnum.class) 
       .addClass(LoggerProducer.class) 
       .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml"); 
    } 

    @Test 
    public void testEnum() { 
     MyEnum myEnum = MyEnum.HI; 
     String greeting = myEnum.getGreeting(); 
     assertThat("Should give the greeting.", greeting, is("Hi there!")); 
    } 

} 

完全可測試的項目都可以在這裏找到,MyEnum.class是原來的問題,MyEnum1.class是沒有注射液(工作,但不是我期待的)和MyEnum2.class是一個建議的答案。

編輯:用工作解決方案更新了GitHub倉庫。 https://github.com/martijnburger/how-to-inject-a-logger-in-an-enum

+1

我想原因是你使用CDI注入記錄儀,它不起作用,因爲你的枚舉不是一個bean =>你的記錄器保持爲空。 –

+1

你怎麼稱呼枚舉?對於注入來使用它所使用的類應該是代理創建的對象。我猜你正在直接調用'MyEnum.HI.getGreeting()',在這種情況下,相應的DI框架將不知道它需要注入一些變量。你可以粘貼你如何調用這個代碼? –

+0

@BandiKishore是的,這就是我使用它的方式。我添加了測試用例。有沒有辦法使用'LoggerProducer'來登錄這種情況? –

回答

1

找到了一個可行的解決方案!

我創建了一個輔助類,如下所示:

public class LoggerHelper { 

    private static Logger logger; 

    private void injectLogger(@Observes @Initialized(ApplicationScoped.class) Object context, 
      Logger logger) { 
     LoggerHelper.logger = logger; 
    } 

    public static Logger getLogger() { 
     return logger; 
    } 

} 

現在,我可以使用注射在枚舉記錄器:

private final Logger log = LoggerHelper.getLogger(); 
2

由於枚舉是靜態的,所以此直接注入將不起作用。 您可以在您的枚舉類

private static final Logger log = Logger.getLogger(Myenum.class.getName()); 
+0

是的。我明白了,而且我知道它是有效的。但問題是,如何使用CDI注入來登錄枚舉。 –

+0

你可以在你的enum類中創建一個內部類LogInjector,並在你的內部類中注入該記錄器 – shubham

+0

你能舉個例子嗎? –

0

枚舉創建一個新的記錄器不能注射,因爲他們是靜態的。

如果你仍然想注入(而不是僅僅創建記錄器),那麼你需要在你的枚舉中創建一個靜態類,它具有setter或構造函數注入。當設置者或構造函數被DI框架調用時,請將它給出的值自行分配給枚舉中的靜態值。

枚舉可以根據需要現在訪問它。但是要小心,如果你的類沒有被注入,那麼這個值將是空的。

事情是這樣的:

public enum MyEnum { 

     HI("Hi there!"), 
     HELLO("Hello mister!"); 

     private static Logger log; 

     private final String greeting; 

     private MyEnum(String greeting) { 
      this.greeting = greeting; 
     } 

     public String getGreeting() { 
      log.debug("Method getGreeting called"); 
      return this.greeting; 
     } 

     @Component 
     public static class InjectionHelper { 
     @Inject 
     public InjectionHelper(Logger log) { 
      MyEnum.log = log; 
     } 
     } 
    } 
+0

謝謝。我仍然得到NPE。請看我最新的問題。怎麼了? 「如果班級還沒有注入」是什麼意思? –

+0

你沒有做我說的。 – john16384

+0

我真的不會這樣做,只是爲了記錄器,但...但它是你的代碼。 – john16384

-1

您可以創建一個集服務類(由相應的DI框架創建 - 說春),注入這個類裏面這個日誌,並在你的枚舉使用它。

這裏是一個示例代碼,它的工作原理。 (換上bean標籤服務註釋這個類在XML中,如果您使用的做這件事的XML方式。您也可以忽略龍目@Getter註釋,並用靜態吸氣更換)

// Service which is actually a Utility class but have DI Managed Beans. 
@Service("staticService") 
public class StaticService { 

    @Getter 
    private static Logger log; 

    @Inject 
    StaticService(Logger log) { 
     StaticService.log = log; 
    } 
} 

現在在相應的枚舉:

public String getGreeting() { 
     StaticService.getLog().debug("Method getGreeting called"); 
     return this.greeting; 
    } 

我用了一個類似的模式爲我的班(在Spring)和注射工作。

邏輯:

  1. 我們首先創建類(單個實例)的一個實例,並且在構造注入所需的變量。
  2. 由於在Spring初始化過程中(在應用程序啓動過程中)調用了這個函數,所以日誌被初始化,我們在構造函數中手動指定log的靜態變量與注入對象。

注:

  1. 不要忘記在構造函數參數數量的進樣註解。
  2. 最好不要爲此日誌對象提供setter方法。由於它的靜態和共享,我們不希望人們在施工後取代這個價值。 (使它最終不是一個選項,因爲它的靜態)。
+0

我使用CDI,而不是春天。但我想我明白你在說什麼,我試了一下。它仍然給我一個getLog()方法的NPE。 –

+0

這很奇怪。如果CDI知道Logger對象,那麼這個方法應該可以工作。與其他任何級別的注射類似。我不確定CDI,但是是否可以有任何註釋(如@Service或XML條目)爲StaticService類創建bean實例?也許你可以添加並看看。 –

+0

我想你的意思是https://docs.oracle.com/javaee/7/api/javax/ejb/Singleton.html –