7

何百人ものユーザーのうち、Java デスクトップ アプリの起動に問題があるのは 1 人だけです。彼にとっては、約3分の1の時間しか始まりません。他の 3 分の 2 の時間は、起動時に NullPointerException がスローされます。

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

スタックトレースをたどったところ、原因が次のとおりであることがわかりました

Thread.currentThread().getContextClassLoader()

JEdi​​torPane では null が返されます。

グーグル検索によると、これは散発的で、非常にまれで、少数の人々に影響を与える不可解な問題であることが明らかになりました。

私の質問は、回避策として何ができますか? EditorPane を作成する前に呼び出すと、これが機能する可能性があります。

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

しかし、私はクラスローダーを自分が望むほどよく理解していません (そして、それらをよりよく理解しようとしました)。EDT で contextClassLoader を変更すると、悪影響が生じる可能性があると思います。

私にできることはありますか?

編集: Java ClassLoaders をよく理解している人と連絡がありました。これはあいまいな ClassLoader 競合状態のようです。つまり、Java のバグです。

4

1 に答える 1

4
Thread.currentThread().getContextClassLoader()

のコードがJEditorPane.registerEditorKitForContentType上記のコードで null の戻り値をチェックしない場合、これは のバグですJEditorPaneMyClass.class.getClassLoader() null を返すこともあることに注意してください。信頼できる唯一のものは、システム ClassLoaderです。

通常、呼び出しのコンテキストを設定するパターンClassLoaderは次のようになります。

Thread thread = Thread.currentThread();
ClassLoader old = thread.getContextClassLoader();
thread.setContextClassLoader(fooClassLoader);
try {
  // do call that depends on context ClassLoader
} finally {
  thread.setContextClassLoader(old);
}

経由で設定する必要がある値はsetContextClassLoader、それを使用しているコードの意図と、ClassLoader実行しているフレームワークの設計によって異なります。

スタンドアロン アプリケーションでは、おそらくこれを使用するだけで問題を解決できますClassLoader(現在のクラスへの ref を渡します)。

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;
}

ClassLoader センシティブなプラグイン フレームワーク (Java EE サーバーが代表的な例です) では、ロード スキームの性質と使用法を理解するのに費用がかかります。

于 2009-12-06T18:21:07.907 に答える