我们有一个桌面Swing应用程序,依赖于Google Guice 4.1.0进行依赖注入。在开发期间一切正常,但当同事尝试运行该应用程序时出现了奇怪的问题。
我们有一个
这在我的电脑上没有发生过,而且我们使用相同的JDK。
以下是
我们有一个
MainWindow
类扩展了JPanel
。在构造函数中,此类使用可注入的控制器。在主方法中创建Guice注入器。然后注入器尝试实例化MainWindow
(injector.getInstance(MainWindow.class)
)。结果失败,并抛出NullPointerException
!这在我的电脑上没有发生过,而且我们使用相同的JDK。
以下是
MainWindow
类被削减到有问题的代码(注意:不幸的是,这不能重现问题):class MainWindow extends JPanel {
private final Foo foo;
private final JFrame frame;
@Inject
public MainWindow(Foo foo) {
super(new GridBagLayout()); // <-- NullPointerException
this.foo = foo;
this.frame = new JFrame("title");
}
public void createAndShowGUI() {
// ...
frame.add(this);
frame.pack();
frame.setVisible(true);
}
}
这里是 main()
方法:
class Main {
private static final Injector injector = Guice.createInjector();
public static void main(String[] args) {
MainWindow mainWindow = injector.getInstance(MainWindow.class);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
mainWindow.createAndShowGUI();
}
});
}
}
以下是异常的堆栈跟踪信息:
com.google.inject.ProvisionException: Unable to provision, see the following errors:
1) Error injecting constructor, java.lang.NullPointerException
at app.gui.MainWindow.<init>(MainWindow.java:133)
while locating app.gui.MainWindow
1 error
at com.google.inject.internal.InjectorImpl$2.get(InjectorImpl.java:1028) ~[app-1.0-SNAPSHOT.jar:?]
at com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1054) ~[app-1.0-SNAPSHOT.jar:?]
at app.Main.createAndShowGUI(Main.java:40) ~[app-1.0-SNAPSHOT.jar:?]
at app.Main.access$000(Main.java:26) ~[app-1.0-SNAPSHOT.jar:?]
at app.Main$2.run(Main.java:67) ~[app-1.0-SNAPSHOT.jar:?]
空指针异常在最出人意料的地方抛出 - 在MainWindow
的超类构造函数调用中(这是第133行)。我开始深入研究,发现手动创建MainWindow
并注入其依赖项是正确的:
MainWindow mainWindow = new MainWindow(injector.getInstance(Foo.class));
我怀疑可能是类加载器没有正确工作,因此我尝试使用MainWindow
和JPanel
的日志类加载器再次尝试:
System.out.println("MainWindow: " + MainWindow.class.getClassLoader());
System.out.println("JPanel: " + JPanel.class.getClassLoader());
MainWindow mainWindow = injector.getInstance(MainWindow.class);
类加载器是不同的(JPanel
由引导程序加载),但现在注入已经正常工作了。我想这是因为现在JPanel
类被显式地加载到主方法上下文中。
所以我的问题是:
- 有人遇到过类似的问题吗?
- 是我的错误,还是一个bug?
- 如果这是一个bug,它会发生在Guice中吗?或者是JRE?
关于Java和操作系统的更多细节:
- 我最初使用JDK 1.8.0u111开发,但后来切换到JDK 1.8.0u121。
- 应用程序编译为Java 6。
- 在我的计算机上(Windows 10,版本1607(OS Build 14393.693),JRE 6和JRE 8(来自JDK)),运行非常顺畅。
- 在同事的计算机上(Windows 10,版本1511(OS Build 10586.753),JDK 1.8.0u112和1.8.0u121),会出现
NullPointerException
。
不幸的是,我无法提供能够重现问题的最小版本。该问题只在同事的环境中发生。
MainWindow
中是否重写了setLayout
、setDoubleBuffered
、setUIProperty
、updateUI
、setLocale
、enableEvents
或其他系统调用?JPanel 在其构造函数中调用了一些可重写方法,这意味着子类可以读取尚未设置的非空终态字段。(另外,我很惊讶你可以在没有父级的JPanel上调用show
,而不是JFrame或其他明确的顶级组件。) - Jeff BowmanToolkit.getDefaultToolkit(); System.setProperty("java.awt.headless", "true");
,而不是你声明MainWindow的位置。2.将注入移动到EDT可运行程序中,并调用,在你的情况下:injector.getInstance(MainWindow.class).createAndShowGUI();
。虽然不确定是否有帮助,但你可以尝试一下。 - rdlopes