JDK-8017776 : Swing Event Thread does not use JNLP class loader
  • Type: Bug
  • Component: deploy
  • Sub-Component: webstart
  • Affected Version: 7u25
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_7
  • Submitted: 2013-06-25
  • Updated: 2014-06-23
  • Resolved: 2013-07-11
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other JDK 6 JDK 7 JDK 8
5.0-poolResolved 6u60Fixed 7u40Fixed 8 b99Fixed
Related Reports
Duplicate :  
Duplicate :  
Duplicate :  
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
java version  " 1.7.0_25 " 
Java(TM) SE Runtime Environment (build 1.7.0_25-b16)
Java HotSpot(TM) Client VM (build 23.25-b01, mixed mode, sharing)


ADDITIONAL OS VERSION INFORMATION :
Have reproduced under Windows 7 64-bit Enterprise SP1; multiple user reports under XP and Vista as well; see Description below

A DESCRIPTION OF THE PROBLEM :
There are two ways to reproduce the problem:

1. Launch an app under Java Web Start 10.25.2.16 from JRE 7u25 but using a Java 6 JRE (i.e. write the JNLP file so that it prefers a Java 6 JRE and ensure one is available in the Java control panel)

2. Run under 7u25 alone with the Java console disabled - I am unable to reproduce this myself but we have done so within our organisation and many users report this issue with only 7u25 installed. For affected users, the problem is always reproducible; I have been unable to determine why this only happens to some users and not others. Enabling the Java console in control panel advanced settings makes the issue go away for all users.

In either case, the EDT will use the JRE default classloader as its context class loader. This causes a number of issues including loading custom look and feel by name, using RMI stub classes and others. The test case below triggers the bug by loading a custom Swing LaF.

REGRESSION.  Last worked in version 7u25

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run an application under Java Web Start and set a custom look and feel (not one provided by the JRE, but one loaded via the JNLP classloader)

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The custom LaF should be installed and used. This is what happens when running under Java Web Start from JRE 7u21 or earlier, or when running outside of Web Start.

When running under JWS from 7u21 or earlier outputting the EDT context classloader shows it is using the JNLP classloader:

Classloader: com.sun.jnlp.JNLPClassLoader@1193779

ACTUAL -
The event thread is not using the Java Web Start class loader and fails to load the custom LaF class

Classloader: sun.misc.Launcher$AppClassLoader@affc70
java.lang.ClassNotFoundException: com.piperoglou.webstartlaftest.WebStartLookAndFeelTestHarness$MyLookAndFeel
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:249)
at javax.swing.SwingUtilities.loadSystemClass(SwingUtilities.java:1850)
at javax.swing.UIManager.setLookAndFeel(UIManager.java:557)
at com.piperoglou.webstartlaftest.WebStartLookAndFeelTestHarness$1.run(WebStartLookAndFeelTestHarness.java:22)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:672)
at java.awt.EventQueue.access$400(EventQueue.java:81)
at java.awt.EventQueue$2.run(EventQueue.java:633)
at java.awt.EventQueue$2.run(EventQueue.java:631)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:87)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:642)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)


ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.lang.ClassNotFoundException: com.piperoglou.webstartlaftest.WebStartLookAndFeelTestHarness$MyLookAndFeel

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
package com.piperoglou.webstartlaftest;

import com.sun.java.swing.plaf.windows.WindowsLookAndFeel;
import java.awt.BorderLayout;
import java.awt.Container;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.WindowConstants;

public class WebStartLookAndFeelTestHarness {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println( " Classloader:  "  + Thread.currentThread().getContextClassLoader());
                    UIManager.setLookAndFeel( " com.piperoglou.webstartlaftest.WebStartLookAndFeelTestHarness$MyLookAndFeel " );
                } catch (Exception e) {
                    e.printStackTrace();
                }

                JTextArea textArea = new JTextArea( " The quick brown fox jumped over the lazy dog. How rude. " , 50, 10);
                textArea.setLineWrap(true);
                textArea.setWrapStyleWord(true);

                JFrame frame = new JFrame( " Java Web Start Look & Feel Test " );
                frame.setBounds(50, 50, 200, 200);
                frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

                Container contentPane = frame.getContentPane();
                contentPane.setLayout(new BorderLayout());
                contentPane.add(textArea, BorderLayout.CENTER);

                frame.setVisible(true);
            }
        });
    }

    public static class MyLookAndFeel extends WindowsLookAndFeel {
        private static final long serialVersionUID = -7686127811595151510L;
    }

}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
- For users that have Java 7u25 installed only, enable the Java Console
- For users that use Java Web Start from Java 7u25 but are using an older JRE, disable the older JRE and the Java Console

Also, in code (Credit for this to Oracle forum user theskad81 from https://forums.oracle.com/thread/2552214 with small changes by myself)

private static void quickAndDirtyFixForProblemWithWebStartInJava7u25() {
        if (! " javaws-10.25.2.16 " .equals(System.getProperty( " javawebstart.version " ))) {
            return;
        }
        LOGGER.info( " Java Web Start 10.25.2.16 (from JRE 7u25) detected - applying classloader fix " );

        final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        try {
            SwingUtilities.invokeAndWait(new Runnable() {
                @Override
                public void run() {
                    try {
                        // Change context in all future threads
                        final Field field = EventQueue.class.getDeclaredField( " classLoader " );
                        field.setAccessible(true);
                        final EventQueue eventQueue = Toolkit.getDefaultToolkit().getSystemEventQueue();
                        field.set(eventQueue, classLoader);
                        // Change context in this thread
                        Thread.currentThread().setContextClassLoader(classLoader);
                    } catch (Exception e) {
                        LOGGER.error( " Unable to apply 'fix' for java 1.7u25 " , e);
                    }
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
Comments
justification: popular 7u25 regression reported in forums and also via customer thru sustaining.
16-07-2013

SQE-OK to get this issue fixed in 7u40.
16-07-2013

This regression is caused by the changes made under JDK-8013410. The problem is that 1.) EventQueue.java has static initialization code that records getContextClassLoader() at the time EventQueue is loaded. 2.) The invocation of AppContextUtil.createApplicationAppContext() from initPreloader() causes the creation of EventQueue, but the thread executes this call does not have the right ContextClassLoader. 3.) Java Web Start then sets the ContextClassLoader of the current AWT EventDispatchThread(). 4.) When running java with any AWT component showing (such as the Java Web Start console) this EventDispatchThread keeps running. 5.) When running java w/o any component showing, this EventDispatchThread dies, and a new one is created when an event is posted. 6.) This new EventDispatchThread dose not have the right ContextClassLoader. The problem can be fixed by inserting call of setContextClassLoader() in initPreLoader: Runnable constructor = new Runnable() { public void run() { Thread.currentThread().setContextClassLoader(cl); AppContextUtil.createApplicationAppContext() doInitPreloader(cl); } };
05-07-2013