2009-12-06 15 views
7

Jeden i tylko jeden z moich setek użytkowników ma problem z uruchomieniem aplikacji komputerowej Java. Zaczyna się dla niego tylko około jednej trzeciej czasu. Pozostałe dwie trzecie czasu NullPointerException zostanie rzucony na starcie:Jak mogę bezpiecznie rozwiązać ten problem z modułem kontekstowym Java?

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) 

Mam następnie ślad stosu, aby dowiedzieć się, że przyczyną jest to, że

Thread.currentThread().getContextClassLoader() 

w JEditorPane zwraca wartość null.

Googling ujawnia, że ​​jest to sporadyczny, bardzo rzadki i tajemniczy problem, który dotyka kilku osób.

Moje pytanie brzmi, co mogę zrobić jako obejście? To może działać, jeśli ja to nazywam przed utworzeniem EditorPane:

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

Ale ja naprawdę nie rozumiem classloaders jak chciałbym (i starałem się je zrozumieć lepiej). Uważam, że zmiana contextClassLoader w EDT może mieć złe konsekwencje.

Jakieś pomysły, co mogę zrobić?

EDYCJA: Miałem trochę korespondencji z kimś, kto dobrze zna Java ClassLoaders. Wygląda na to, że jest to mało znany warunek wyścigowy ClassLoader. To jest błąd w Javie.

+0

Czy masz szansę na uaktualnienie środowiska wykonawczego Java? –

+0

@ Tamás, jest to aplikacja na Maca. Poprosiłem go o wypróbowanie najnowszej aktualizacji Mac Java. –

Odpowiedz

4
Thread.currentThread().getContextClassLoader() 

Jeśli kod w JEditorPane.registerEditorKitForContentType nie sprawdza wartość null powrotnego w powyższym kodzie, to jest to błąd w JEditorPane. Zauważ, że MyClass.class.getClassLoader() . Jedynym, na którym można polegać, jest system ClassLoader.

Wzór do ustawiania kontekstu ClassLoader dla wywołania zwykle wygląda mniej więcej tak:

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

wartość, która powinna zostać ustalona poprzez setContextClassLoader zależy od intencji kodu, który zużywa go i projektowanie . ram ClassLoader używasz w

w aplikacji autonomicznej, prawdopodobnie można uciec tylko za pomocą tego ClassLoader (przechodzącą w odnośniku do bieżącej klasy):

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

W wrażliwym na ClassLoadera środowisku wtyczek (najlepszym przykładem jest serwer Java EE), warto byłoby zrozumieć charakter i sposób korzystania z schematu ładowania.

+0

Próbowałem podanego wzorca do ustawiania modułu ładującego klasy dla wywołania. Podoba mi się, ponieważ nie zepsuje rzeczy potencjalnie do innych zastosowań programu contextclassloader. –

Powiązane problemy