Wir haben eine Desktop-Swing-Anwendung mit Google Guice 4.1.0 Dependency-Injection. Während der Entwicklung funktionierte alles gut, aber etwas seltsames passierte, als ein Kollege versuchte, die Anwendung auszuführen.
Wir haben eine Klasse MainWindow
, die JPanel
erweitert. Im Konstruktor übernimmt diese Klasse einige Controller, die selbst injizierbar sind. In der Hauptmethode Guice Injektor wird erstellt. Dann versucht der Injektor, MainWindow
( injector.getInstance(MainWindow.class)
) zu instanziieren. Und es ist mit NullPointerException
fehlgeschlagen!
Dies passiert nicht auf meinem Computer, und wir verwenden dasselbe JDK.
Hier ist MainWindow
class auf problematischen Code reduziert (Hinweis: Dies reproduziert das Problem leider nicht):
Und hier ist main()
Methode:
Hier ist Stack-Trace der Ausnahme:
%Vor% Die NPE wurde an der überraschendsten Stelle geworfen - im Aufruf des Konstruktors der Oberklasse von MainWindow
(das ist Zeile 133). Ich fing an zu graben und fand heraus, dass die manuelle Erstellung von MainWindow
und das Injizieren der Abhängigkeiten korrekt funktioniert:
Ich vermutete, dass der Klassenlader nicht korrekt funktionierte, also versuchte ich es erneut mit dem Classloader von MainWindow
und JPanel
:
Klassenlader sind anders ( JPanel
wird vom Bootstrap geladen), aber jetzt hat die Injektion richtig funktioniert. Ich nehme an, das liegt daran, dass JPanel
class jetzt explizit in den Hauptmethodenkontext geladen wurde.
Meine Fragen sind also:
Weitere Details zu Java und Betriebssystem:
NullPointerException
wird auf dem Computer des Kollegen mit Windows 10, Version 1511 (OS Build 10586.753), JDK 1.8.0u112 und 1.8.0u121 ausgelöst. Leider konnte ich keine minimale Version bereitstellen, die das Problem reproduziert. Verdammt, ich kann das Problem nicht reproduzieren, es passiert nur in der Umgebung des Kollegen.
Ich vermute sehr, dass dies auf eine Wettlaufsituation zurückzuführen ist. Swing-Komponenten sind nicht Thread-sicher und sollten auf dem EDT gemäß dem Swing-Paket Javadoc :
Swing-Threading-Richtlinie
Generell ist Swing nicht threadsicher. Alle Swing-Komponenten und verwandte Klassen, sofern nicht anders dokumentiert, müssen auf der Veranstaltung zugegriffen werden Thread wird gesendet. Typische Swing-Anwendungen verarbeiten in Antwort auf ein Ereignis, das von einer Benutzergeste erzeugt wird. Beispielsweise, Durch Klicken auf ein JButton werden alle ActionListeners benachrichtigt, die zu JButton. Wie alle Ereignisse, die von einer Benutzergeste erzeugt werden, werden angestellt Der Event - Dispatching - Thread wird von den meisten Entwicklern nicht beeinflusst Einschränkung.
Wo die Wirkung liegt, ist jedoch, einen Swing zu konstruieren und zu zeigen Anwendung. Ruft die Hauptmethode einer Methode oder Methoden in Applet, werden nicht im Event-Dispatching-Thread aufgerufen. Als solches muss übergeben werden, um die Kontrolle an den Event-Dispatching-Thread zu übertragen, wenn Erstellen und Anzeigen einer Anwendung oder eines Applets. Der bevorzugte Weg Um die Kontrolle zu übertragen und mit Swing arbeiten zu können, ist zu verwenden invokeLater. Die invokeLater-Methode plant ein Runnable-Objekt verarbeitet auf dem Event-Dispatching-Thread.
(Hervorhebung von mir)
Jetzt starten Sie die Benutzeroberfläche in der EDT mit invokeLater
, wie auch immer Sie die Benutzeroberfläche auf dem Hauptthread erstellen (durch einen Guice Injector-Aufruf).
Der Guice-Injektor-Aufruf sollte auch im invokeLater
-Teil sein, um die Benutzeroberfläche zu starten.
Tags und Links java swing nullpointerexception classloader guice