Guice kann die Klasse, die JPanel - NPE beim Aufruf des Superkonstruktors erweitert, nicht instanziieren

8

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):

%Vor%

Und hier ist main() Methode:

%Vor%

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:

%Vor%

Ich vermutete, dass der Klassenlader nicht korrekt funktionierte, also versuchte ich es erneut mit dem Classloader von MainWindow und JPanel :

%Vor%

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:

  1. Hat jemand ein ähnliches Problem?
  2. Ist es mein Fehler oder ist es ein Fehler?
  3. Wenn es ein Fehler ist, passiert das in Guice? Oder vielleicht JRE?

Weitere Details zu Java und Betriebssystem:

  • Ich habe es ursprünglich mit JDK 1.8.0u111 entwickelt, bin dann aber zu JDK 1.8.0u121 gewechselt.
  • Die Anwendung wurde nach Java 6 kompiliert.
  • Läuft fehlerfrei auf meinem Computer mit Windows 10, Version 1607 (OS Build 14393.693), auf JRE 6 und JRE 8 (von JDK).
  • 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.

    
Archie 28.02.2017, 10:48
quelle

1 Antwort

1

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.

    
bowmore 15.06.2017 19:34
quelle