7 Stimmen

Wie kann ich dieses Java-Kontext-Classloader-Problem sicher lösen?

Nur einer meiner hunderten Benutzer hat Probleme beim Starten meiner Java-Desktop-App. Es startet nur etwa ein Drittel der Zeit für ihn. Die anderen zwei Drittel der Zeit wird eine NullPointerException beim Starten geworfen:

Ausnahme im Thread "AWT-EventQueue-0" java.lang.NullPointerException
    bei java.util.Hashtable.put(Hashtable.java:394)
    bei javax.swing.JEditorPane.registerEditorKitForContentType(JEditorPane.java:1327)
    bei javax.swing.JEditorPane.registerEditorKitForContentType(JEditorPane.java:1309)
    bei javax.swing.JEditorPane.loadDefaultKitsIfNecessary(JEditorPane.java:1387)
    bei javax.swing.JEditorPane.getKitTypeRegistry(JEditorPane.java:1344)
    bei javax.swing.JEditorPane.getEditorKitClassNameForContentType(JEditorPane.java:1340)
    bei javax.swing.JTextPane.(JTextPane.java:76)
    bei myapp.Launcher$1.run(Launcher.java:13)
    bei java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
    bei java.awt.EventQueue.dispatchEvent(EventQueue.java:633)
    bei java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:296)
    bei java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:211)
    bei java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:201)
    bei java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:196)
    bei java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:188)
    bei java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

Ich habe den Aufrufstapel verfolgt, um herauszufinden, dass die Ursache darin liegt, dass

Thread.currentThread().getContextClassLoader()

in JEditorPane null zurückgibt.

Ein Google-Suche ergibt, dass es sich um ein sporadisches, sehr seltenes und mysteriöses Problem handelt, das einige Leute betrifft.

Meine Frage ist, was kann ich als Workaround tun? Folgendes könnte funktionieren, wenn ich es vor dem Erstellen eines EditorPanes aufrufe:

Thread.currentThread().setContextClassLoader(MyClass.class.getClassLoader());

Aber ich verstehe Klassenlader nicht wirklich so gut, wie ich möchte (und habe versucht, sie besser zu verstehen). Ich habe das Gefühl, dass eine Änderung des contextClassLoader im EDT negative Auswirkungen haben könnte.

Habt ihr Ideen, was ich tun kann?

EDIT: Ich hatte einige Korrespondenz mit jemandem, der Java-ClassLoader gut versteht. Es scheint, dass dies ein obskurer ClassLoader-Rennzustand ist. Das heißt, ein Fehler in Java.

0 Stimmen

Besteht die Möglichkeit, das Java-Laufzeitumgebung des Benutzers zu aktualisieren?

0 Stimmen

@Tamás, dies ist eine Mac-App. Ich habe ihn gebeten, das neueste Mac Java-Update auszuprobieren.

4voto

McDowell Punkte 105255
Thread.currentThread().getContextClassLoader()

Wenn der Code in JEditorPane.registerEditorKitForContentType nicht nach einem null-Rückgabewert im obigen Code überprüft, handelt es sich um einen Fehler in JEditorPane. Beachten Sie, dass MyClass.class.getClassLoader() [eventuell auch null zurückgeben kann](http://java.sun.com/javase/6/docs/api/java/lang/Class.html#getClassLoader()). Auf den einzigen, auf den Sie sich verlassen können, ist der [System-ClassLoader](http://java.sun.com/j2se/1.4.2/docs/api/java/lang/ClassLoader.html#getSystemClassLoader()).

Das Muster zum Setzen des Kontexts ClassLoader für einen Aufruf sieht normalerweise so aus:

Thread thread = Thread.currentThread();
ClassLoader old = thread.getContextClassLoader();
thread.setContextClassLoader(fooClassLoader);
try {
  // Aufruf, der vom Kontext-ClassLoader abhängt
} finally {
  thread.setContextClassLoader(old);
}

Der Wert, der über setContextClassLoader gesetzt werden sollte, hängt von der Absicht des Codes ab, der ihn verwendet, und vom Design des ClassLoader-Frameworks, in dem Sie arbeiten.

In einer eigenständigen Anwendung können Sie wahrscheinlich damit davonkommen, einfach diesen ClassLoader zu verwenden (indem Sie eine Referenz zur aktuellen Klasse übergeben):

private ClassLoader findClassLoaderForContext(Class c) {
  ClassLoader context = Thread.currentThread().getContextClassLoader();
  ClassLoader me = c.getClassLoader();
  ClassLoader system = ClassLoader.getSystemClassLoader();
  return (context == null) ? (me == null) ? system : me : context;
}

In einem ClassLoader-sensiblen Plug-in-Framework (ein Java-EE-Server wäre ein gutes Beispiel) wäre es ratsam, die Art und Nutzung des Ladeschemas zu verstehen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X