How can I safely solve this Java context classloader problem?

亡梦爱人 提交于 2020-01-12 05:22:10

问题


One and only one of my hundreds of users has trouble starting my Java desktop app. It only starts for him about one-third of the time. The other two-thirds of the time a NullPointerException is thrown at startup:

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)

I've followed the stack trace to find that the cause is that

Thread.currentThread().getContextClassLoader()

in JEditorPane is returning null.

Googling reveals that this is a sporadic, very infrequent, and mysterious problem that affects a few people.

My question is, what can I do as a work-around? This might work, if I call it before creating an EditorPane:

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

But I don't really understand classloaders as well as I would like (and I've tried to understand them better). I feel that changing the contextClassLoader in the EDT could have bad ramifications.

Any ideas what I can do?

EDIT: I had some correspondence with someone who understands Java ClassLoaders well. It seems this is an obscure ClassLoader race condition. That is, a bug in Java.


回答1:


Thread.currentThread().getContextClassLoader()

If the code in JEditorPane.registerEditorKitForContentType does not check for a null return value in the above code, this is a bug in JEditorPane. Note that MyClass.class.getClassLoader() may also return null. The only one you can rely on is the system ClassLoader.

The pattern for setting the context ClassLoader for an invocation usually looks something like this:

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

The value that should be set via setContextClassLoader will depend on the intent of the code that is consuming it and the design of the ClassLoader framework you are running in.

In a stand-alone application, you can probably get away with just using this ClassLoader (passing in a ref to the current class):

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 a ClassLoader-sensitive plug-in framework (a Java EE server would be a prime example), it would pay to understand the nature and usage of the loading scheme.



来源:https://stackoverflow.com/questions/1855808/how-can-i-safely-solve-this-java-context-classloader-problem

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!