如何在枚举中注入Logger

时间:2017-01-21 12:14:20

标签: java cdi

当我尝试在枚举中注入我的Logger生成器时,我得到了一个N​​PE。如何在枚举中注入Logger?

示例:

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行时,它就可以正常工作。

Testcase看起来像这样:

@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是无注入的解决方案(正常工作,但不是我要查找的内容)和{{1}是一个建议的答案。

编辑:使用有效的解决方案更新了GitHub仓库。 https://github.com/martijnburger/how-to-inject-a-logger-in-an-enum

4 个答案:

答案 0 :(得分:2)

由于枚举是静态的,这种直接注射不起作用。 您可以在枚举类中创建一个新的记录器

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

答案 1 :(得分:2)

找到一个有效的解决方案!

我创建了一个帮助类,如下所示:

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

}

现在我可以使用以下方法在Enum中注入记录器:

private final Logger log = LoggerHelper.getLogger();

答案 2 :(得分:0)

不能注射枚举,因为它们是静态的。

如果您仍想要注入(而不是仅仅创建Logger),那么您需要在枚举中创建一个静态类,该类具有setter或构造函数注入。当DI框架调用setter或构造函数时,取其给出的值并将其自己分配给枚举中的静态值。

枚举可以根据需要立即访问它。但要注意,如果您的课程尚未注入,则该值将为null。

这样的事情:

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

答案 3 :(得分:-1)

你可以创建一个Singleton Service类(由你自己的DI框架创建 - 比如Spring),在该类中注入这个日志并在你的枚举中使用它。

这是一个有效的示例代码。 (如果您正在使用XML方法,那么用XML替换此类的bean标记,如果您正在使用XML方法。也可以忽略lombok @Getter注释并用静态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;
    }

我在我的一个类(In Spring)中使用了类似的模式,并且注入工作正常。

逻辑:

  1. 我们首先创建一个类的实例(单例实例)并在构造函数中注入所需的变量。
  2. 由于在Spring初始化期间(在应用程序启动期间)调用此函数,因此初始化日志并在构造函数中手动为注入的对象分配log的静态变量。
  3. 注意:

    1. 不要忘记构造函数Args中的Inject注释。
    2. 最好不要为此日志对象提供setter方法。由于其静态和共享,我们不希望人们在构建后替换此值。 (将其作为最终版本不是一个选项,因为它的静态)。