java Guice 注入空指针

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13298128/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 12:11:32  来源:igfitidea点击:

Guice injection null pointer

javanullpointerexceptionguicecode-injection

提问by user1810567

We try to refactoring a project with Guice. The idea is to bind all the Languageinterface to a concreate object like Frenchor Polish.

我们尝试用 Guice 重构一个项目。这个想法是将所有Language接口绑定到一个 concreate 对象,比如FrenchPolish

We have a module for binding:

我们有一个用于绑定的模块:

public class StandardModule extends AbstractModule {

    @Override
    protected void configure() {

       bind(Language.class).to(Polish.class);

    }
 }

And a classe (AboutDialog.java) that use this injected object :

还有一个使用这个注入对象的类(AboutDialog.java):

@Inject Language language;

public AboutDialog(JFrame parent) {
    super(parent, "", true);
    this.language=language;
    this.setTitle(language.getLanguageInUse().getString("AboutDialog.title"));
    this.parent = parent;
    try {
        jbInit();
    } catch (Exception e) {
        e.printStackTrace();
    }
    pack();
}

And we have as result:

结果是:

java.lang.NullPointerException at net.sf.jmoney.gui.AboutDialog.<init>(AboutDialog.java:67)

Line 67 is:

第 67 行是:

this.setTitle(language.getLanguageInUse().getString("AboutDialog.title"));

Our interface is:

我们的界面是:

public interface Language {

    public ResourceBundle getLanguageInUse();
}

And the Polish class is:

波兰语课是:

public class Polish implements Language {

    private ResourceBundle languageInUse;

    public Polish() {
        languageInUse = ResourceBundle.getBundle(Constants.LANGUAGE_PL);
    }

    public ResourceBundle getLanguageInUse() {
        return languageInUse;
    }


}

We are lost...

我们迷路了...

采纳答案by Daniel Manzke

I assume that your are not creating your AboutDialogwith the help of Guice.

我假设您不是AboutDialog在 Guice 的帮助下创建的。

What you could do is use injector.injectMembers(this)where thisis the AboutDialog.

你可以做的是使用injector.injectMembers(this)where thisis the AboutDialog.

The best way would be that the AboutDialogwill be created by Guice, so all members will be injected.

最好的方法是AboutDialog由 Guice 创建,因此所有成员都将被注入。

回答by Jeff Bowman

You're using "field injection". This will make it hard to use your injected values in a constructor; even if Guice were to create the object (which is not happening now) or you were to use injector.injectMembers(aboutDialog), the constructor would run before the injector has a chance to inject the field you want.

您正在使用“现场注入”。这将使在构造函数中使用注入的值变得困难;即使 Guice 要创建对象(现在不会发生)或者您要使用injector.injectMembers(aboutDialog),构造函数也会在注入器有机会注入您想要的字段之前运行。

It's a little more tricky to create a class that takes a varying parameter as well as an injected parameter. This leaves you with a few options:

创建一个接受可变参数和注入参数的类有点棘手。这让您有几个选择:

  • Inject the JFrame. If you know what JFrame you're going to use when the constructor is being created, then just use bind(JFrame.class).toInstance(myJFrame);in your Module. Then Guice can create the AboutDialog entirely.

  • Create a Factory manually. That way you can inject AboutDialog.Factoryand just call createto get your AboutDialog. It'll look something like this:

    public class AboutDialog extends JDialog {
    
      /** Injectable factory. */
      public static class Factory {
        @Inject private Language language;
    
        public AboutDialog create(JFrame parent) {
          return new AboutDialog(parent, language);
        }
      }
    
      // no @Inject parameter; you're calling "new" yourself above!
      public AboutDialog(JFrame parent, Language language) {
        super(parent, "", true);
        this.language = language;
        // ... other initialization
      }
    }
    
  • Create a Factory and let Guice wire it up for you via assisted injection.

    public class AboutDialog extends JDialog {
    
      public interface Factory {
        public AboutDialog create(JFrame parent);
      }
    
      // you need the @Inject, and also the @Assisted to tell Guice to
      // use the parameter instead of Guice bindings
      @Inject
      public AboutDialog(@Assisted JFrame parent, Language language) {
        super(parent, "", true);
        this.language = language;
        // ... other initialization
      }
    }
    
    public class StandardModule extends AbstractModule {
      @Override protected void configure() {
        bind(Language.class).to(Polish.class);
    
        // here every method in AboutDialog.Factory will be implemented
        // to create the method's return type [AboutDialog] based on
        // the parameters (like JFrame) and the bindings (like Language)
        install(new FactoryModuleBuilder().build(AboutDialog.Factory.class));
      }
    }
    
  • 注入 JFrame。如果您知道在创建构造函数时将使用什么 JFrame,那么只需bind(JFrame.class).toInstance(myJFrame);在您的模块中使用即可。然后Guice 可以完全创建AboutDialog。

  • 手动创建工厂。这样您就可以注入AboutDialog.Factory并调用create以获取您的AboutDialog. 它看起来像这样:

    public class AboutDialog extends JDialog {
    
      /** Injectable factory. */
      public static class Factory {
        @Inject private Language language;
    
        public AboutDialog create(JFrame parent) {
          return new AboutDialog(parent, language);
        }
      }
    
      // no @Inject parameter; you're calling "new" yourself above!
      public AboutDialog(JFrame parent, Language language) {
        super(parent, "", true);
        this.language = language;
        // ... other initialization
      }
    }
    
  • 创建一个工厂,让 Guice 通过辅助注射为您连接起来。

    public class AboutDialog extends JDialog {
    
      public interface Factory {
        public AboutDialog create(JFrame parent);
      }
    
      // you need the @Inject, and also the @Assisted to tell Guice to
      // use the parameter instead of Guice bindings
      @Inject
      public AboutDialog(@Assisted JFrame parent, Language language) {
        super(parent, "", true);
        this.language = language;
        // ... other initialization
      }
    }
    
    public class StandardModule extends AbstractModule {
      @Override protected void configure() {
        bind(Language.class).to(Polish.class);
    
        // here every method in AboutDialog.Factory will be implemented
        // to create the method's return type [AboutDialog] based on
        // the parameters (like JFrame) and the bindings (like Language)
        install(new FactoryModuleBuilder().build(AboutDialog.Factory.class));
      }
    }
    

As noted in the question comments, make sure you're getting your AboutDialog(or AboutDialog.Factoryvia an @Injected constructor/field or from the Injectoritself, or else Guice will not know to inject the parameters.

如问题评论中所述,请确保您正在获取您的AboutDialog(或AboutDialog.Factory通过@Injected 构造函数/字段或从其Injector本身获取,否则 Guice 将不知道注入参数。