17

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

我们有一个绑定模块:

public class StandardModule extends AbstractModule {

    @Override
    protected void configure() {

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

    }
 }

还有一个使用这个注入对象的类(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();
}

结果是:

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

第 67 行是:

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

我们的界面是:

public interface Language {

    public ResourceBundle getLanguageInUse();
}

波兰语课是:

public class Polish implements Language {

    private ResourceBundle languageInUse;

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

    public ResourceBundle getLanguageInUse() {
        return languageInUse;
    }


}

我们迷路了...

4

2 回答 2

13

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

创建一个接受变化参数和注入参数的类有点棘手。这给您留下了几个选择:

  • 注入 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));
      }
    }
    

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

于 2012-11-09T03:21:36.637 回答
11

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

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

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

于 2012-11-08T21:46:05.617 回答