JDK-6393307 : SWAT: MouseButtonExTest fails in b74 (due to exception in JPasswordField)
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 6
  • Priority: P1
  • Status: Closed
  • Resolution: Fixed
  • OS:
    generic,linux,solaris,solaris_2.5.1,solaris_8,solaris_9,solaris_10 generic,linux,solaris,solaris_2.5.1,solaris_8,solaris_9,solaris_10
  • CPU: generic,x86,sparc
  • Submitted: 2006-03-02
  • Updated: 2012-03-23
  • Resolved: 2006-03-23
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.
JDK 6
6 b78Fixed
Related Reports
Duplicate :  
Duplicate :  
Duplicate :  
Duplicate :  
Duplicate :  
Duplicate :  
Duplicate :  
Duplicate :  
Relates :  
Description
Java Version: 1.6.0-beta2-b74
Platforms: applebee.sfbay SuSE linux9.3(x86-64) 2.6.11.4.21.9 default GNU/linux

Problems:
The test fails in b74 and PASS in b73/72, the test is to To check whether
getModifiersEx() returns the extended Modifiers flag for this event.
Extended Modifiers represent state of all Mouse buttons just after the
event occured.

Looks like it only fails in linux platforms, it PASS winXPpro and solaris10 in b74.

The test case as following:
/**
 * test 1.0 2001/08/12
 * @summary To check whether
 *		    getModifiersEx() returns the extended Modifiers flag for this event.
 *		    Extended Modifiers represent state of all Mouse buttons just after the
 *                   event occured.
 *
 * @author Vishal Byakod(###@###.###) area= AWT
 * @run applet MouseButtonExTest.html
 */
import java.awt.*;
import java.awt.event.*;

public class MouseButtonExTest extends MouseAdapter {
    
    private Frame frame;
    private Panel panel;
    private Button button;
    private Label label;
    private List list;
    private Choice choice;
    private Checkbox checkbox;
    private Scrollbar scrollbar;
    private TextField textfield;
    private TextArea textarea;
    private Component[] components;
    private Component testedComponent;
    
    private int[] keyTypes;
    private String[] keyNames;
    private int[] keyMasks;
    
    private int[] mouseButtonTypes = {
        InputEvent.BUTTON1_MASK,
        InputEvent.BUTTON2_MASK,
        InputEvent.BUTTON3_MASK
    };
    private String[] mouseButtonNames = {
        "BUTTON1",
        "BUTTON2",
        "BUTTON3"
    };
    
    private int mouseMasks[] = {
        InputEvent.BUTTON1_DOWN_MASK,
        InputEvent.BUTTON2_DOWN_MASK,
        InputEvent.BUTTON3_DOWN_MASK
    };

    private static String WORK_DIR = ".";
    private int delay = 500;
    private int keyDelay = 50;
    
    private boolean passed = true;
    private int modifier = 0;
    
    private Object lock = new Object();
    private boolean eventFired = false;
    
    public MouseButtonExTest() {
        if (System.getProperty("os.name").toUpperCase().equals("SUNOS") && 
            ! (System.getProperty("os.arch").equals("x86") || 
               System.getProperty("os.arch").equals("amd64"))) {
            keyTypes = new int[] {
                KeyEvent.VK_CONTROL,
                KeyEvent.VK_SHIFT,
                KeyEvent.VK_META
            };
            keyNames = new String[] {
                "CONTROL",
                "SHIFT",
                "META"
            };
            keyMasks = new int[] {
                InputEvent.CTRL_DOWN_MASK,
                InputEvent.SHIFT_DOWN_MASK,
                InputEvent.META_DOWN_MASK
            };
        } else if (System.getProperty("os.name").toUpperCase().startsWith("WIN")) {
            keyTypes = new int[] {
                KeyEvent.VK_CONTROL,
                KeyEvent.VK_SHIFT,
                KeyEvent.VK_ALT
            };
            keyNames = new String[] {
                "CONTROL",
                "SHIFT",
                "ALT"
            };
            keyMasks = new int[] {
                InputEvent.CTRL_DOWN_MASK,
                InputEvent.SHIFT_DOWN_MASK,
                InputEvent.ALT_DOWN_MASK
            };
        } else {
            keyTypes = new int[] {
                KeyEvent.VK_CONTROL,
                KeyEvent.VK_SHIFT
            };
            keyNames = new String[] {
                "CONTROL",
                "SHIFT"
            };
            keyMasks = new int[] {
                InputEvent.CTRL_DOWN_MASK,
                InputEvent.SHIFT_DOWN_MASK
            };
        }
        try {
            Toolkit.getDefaultToolkit().getSystemEventQueue().invokeAndWait(new Runnable() {
                public void run() {
                    initializeGUI();
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }
    }
    
    private void initializeGUI() {
        frame = new Frame("Test Frame");
        frame.setLayout(new FlowLayout());

        panel = new Panel();
        button = new Button("Button");
        label = new Label("Label");
        list = new List();
        list.add("One");
        list.add("Two");
        list.add("Three");
        choice = new Choice();
        choice.add("Red");
        choice.add("Orange");
        choice.add("Yellow");
        checkbox = new Checkbox("Checkbox");
        scrollbar = new Scrollbar(Scrollbar.HORIZONTAL, 0, 1, 0, 255);
        textfield = new TextField(15);
        textarea = new TextArea(5, 15);
        
        components = new Component[] {
            panel, button, label, list, choice, checkbox, scrollbar, textfield, textarea
        };

        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent event) {
                System.err.println("User closed the window");
                System.exit(1);
            }
        });
        
        for (int i = 0; i < components.length; i++) {
            components[i].addMouseListener(this);
            frame.add(components[i]);
        }
        frame.setSize(300, 300);
        frame.setVisible(true);
    }
    
    public static void main(String[] args) {
        WORK_DIR = System.getProperty("resultsDir");
        if (WORK_DIR == null || WORK_DIR.equals("")) {
            System.err.println("ERROR: resultsDir not set!");
            System.exit(1);
        }
        try {
            MouseButtonExTest test = new MouseButtonExTest();
            test.doTest();
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }
    }
    
    public void mousePressed(MouseEvent event) {
        if (! event.getSource().equals(testedComponent)) {
            return;
        }
        modifier = event.getModifiersEx();
        eventFired = true;
        synchronized (lock) {
            try {
                lock.notifyAll();
            } catch (Exception e) {
            }
        }
    }
    
    private void doTest() throws Exception {
        Robot robot = null;
        try {
            robot = new Robot();
            Thread.sleep(delay * 10);
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }
        
        int keysToTest = keyTypes.length - 2;
        
        for (int i = 0; i < components.length; i++) {
            testedComponent = components[i];
            robot.mouseMove((int) components[i].getLocationOnScreen().x + components[i].getSize().width / 2,
                            (int) components[i].getLocationOnScreen().y + components[i].getSize().height / 2);
            robot.delay(delay);
            robot.mousePress(InputEvent.BUTTON1_MASK);
            robot.delay(delay);
            robot.mouseRelease(InputEvent.BUTTON1_MASK);
            robot.delay(delay);
            robot.keyPress(KeyEvent.VK_ESCAPE);
            robot.delay(keyDelay);
            robot.keyRelease(KeyEvent.VK_ESCAPE);
            robot.delay(delay * 5);
        
            for (int j = 0; j < keysToTest; j++) {
                for (int k = 0; k < mouseButtonTypes.length; k++) {
                    eventFired = false;
                    robot.keyPress(keyTypes[j]);
                    robot.delay(keyDelay);
                    robot.mousePress(mouseButtonTypes[k]);
                    robot.delay(delay);
                    
                    if (! eventFired) {
                        synchronized (lock) {
                            try {
                                lock.wait(delay * 5);
                            } catch (Exception e) {
                            }
                        }
                    }
                    if (eventFired) {
                        if ((keyMasks[j] | mouseMasks[k]) != modifier) {
                            System.err.println("FAIL: getModifiersEx failed. Component: " + 
                                               components[i].getClass() + " Key: " + 
                                               keyNames[j] + " MouseButton: " + 
                                               mouseButtonNames[k]);
                            passed = false;
                        }
                    } else {
                        System.err.println("FAIL: Event was not fired. Component: " + 
                                           components[i].getClass() + " Key: " + 
                                           keyNames[j] + " MouseButton: " + 
                                           mouseButtonNames[k]);
                        passed = false;
                    }
                    
                    robot.mouseRelease(mouseButtonTypes[k]);
                    robot.delay(delay);
                    robot.keyRelease(keyTypes[j]);
                    robot.delay(keyDelay);

                    robot.keyPress(KeyEvent.VK_ESCAPE);
                    robot.delay(keyDelay);
                    robot.keyRelease(KeyEvent.VK_ESCAPE);
                    robot.delay(keyDelay);
                }
            }
        }
            
        if (! passed) {
            System.err.println("Test failed!");
            captureScreenAndSave();
            System.exit(1);
        } else {
            System.out.println("Test passed!");
            System.exit(0);
        }
    }

    /**
     * Do screen capture and save it as image
     */
    private static void captureScreenAndSave() {
     
        try {
            Robot robot = new Robot();
            Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
            Rectangle rectangle = new Rectangle(0, 0, screenSize.width, screenSize.height);
            System.out.println("About to screen capture - " + rectangle);
            java.awt.image.BufferedImage image = robot.createScreenCapture(rectangle);
            javax.imageio.ImageIO.write(image, "jpg", new java.io.File(WORK_DIR, 
                                                                       "ScreenImage.jpg"));
            robot.delay(3000);
        } catch (Throwable t) {
            System.out.println("WARNING: Exception thrown while screen capture!");
            t.printStackTrace();
        }
    }
}
*** (#1 of 2): 2006-03-02 15:04:48 PST ###@###.###

Execptions as followings:
java.lang.reflect.InvocationTargetException
	at java.awt.EventQueue.invokeAndWait(EventQueue.java:994)
	at MouseButtonExTest.<init>(MouseButtonExTest.java:110)
	at MouseButtonExTest.main(MouseButtonExTest.java:167)
Caused by: java.lang.NullPointerException
	at javax.swing.JPasswordField.customSetUIProperty(JPasswordField.java:337)
	at javax.swing.LookAndFeel.installProperty(LookAndFeel.java:150)
	at javax.swing.plaf.basic.BasicPasswordFieldUI.installDefaults(BasicPasswordFieldUI.java:58)
	at javax.swing.plaf.basic.BasicTextUI.installUI(BasicTextUI.java:686)
	at javax.swing.plaf.basic.BasicTextFieldUI.installUI(BasicTextFieldUI.java:57)
	at sun.awt.X11.XTextFieldPeer$AWTTextFieldUI.installUI(XTextFieldPeer.java:493)
	at javax.swing.JComponent.setUI(JComponent.java:613)
	at sun.awt.X11.XTextFieldPeer$XAWTTextField.updateUI(XTextFieldPeer.java:660)
	at javax.swing.text.JTextComponent.<init>(JTextComponent.java:305)
	at javax.swing.JTextField.<init>(JTextField.java:207)
	at javax.swing.JPasswordField.<init>(JPasswordField.java:116)
	at javax.swing.JPasswordField.<init>(JPasswordField.java:74)
	at sun.awt.X11.XTextFieldPeer$XAWTTextField.<init>(XTextFieldPeer.java:604)
	at sun.awt.X11.XTextFieldPeer.<init>(XTextFieldPeer.java:59)
	at sun.awt.X11.XToolkit.createTextField(XToolkit.java:757)
	at java.awt.TextField.addNotify(TextField.java:205)
	at java.awt.Container.addNotify(Container.java:2500)
	at java.awt.Window.addNotify(Window.java:528)
	at java.awt.Frame.addNotify(Frame.java:479)
	at java.awt.Window.show(Window.java:711)
	at java.awt.Component.show(Component.java:1406)
	at java.awt.Component.setVisible(Component.java:1359)
	at java.awt.Window.setVisible(Window.java:694)
	at MouseButtonExTest.initializeGUI(MouseButtonExTest.java:157)
	at MouseButtonExTest.access$000(MouseButtonExTest.java:14)
	at MouseButtonExTest$1.run(MouseButtonExTest.java:112)
	at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:199)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:597)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:273)
	at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:183)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:173)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:168)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:160)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:121)
*** (#2 of 2): 2006-03-02 15:11:56 PST ###@###.###



SunTea applet fails to load due to the same reason
JDS3/solaris10/mz1.7/jre-b76

Java console
-----------

Java Plug-in 1.6.0-beta2
Using JRE version 1.6.0-beta2 Java HotSpot(TM) Client
VM
User home directory = /


----------------------------------------------------
c:   clear console window
f:   finalize objects on finalization queue
g:   garbage collect
h:   display this help message
l:   dump classloader list
m:   print memory usage
o:   trigger logging
p:   reload proxy configuration
q:   hide console
r:   reload policy configuration
s:   dump system and deployment properties
t:   dump thread list
v:   dump thread stack
x:   clear classloader cache
0-5: set trace level to <n>
----------------------------------------------------

java.lang.NullPointerException
	at
javax.swing.JPasswordField.customSetUIProperty(JPasswordField.java:337)
	at
javax.swing.LookAndFeel.installProperty(LookAndFeel.java:150)
	at
javax.swing.plaf.basic.BasicPasswordFieldUI.installDefaults(BasicPasswordFieldUI.java:58)
	at
javax.swing.plaf.basic.BasicTextUI.installUI(BasicTextUI.java:686)
	at
javax.swing.plaf.basic.BasicTextFieldUI.installUI(BasicTextFieldUI.java:57)
	at
sun.awt.X11.XTextFieldPeer$AWTTextFieldUI.installUI(XTextFieldPeer.java:493)
	at javax.swing.JComponent.setUI(JComponent.java:613)
	at
sun.awt.X11.XTextFieldPeer$XAWTTextField.updateUI(XTextFieldPeer.java:660)
	at
javax.swing.text.JTextComponent.<init>(JTextComponent.java:305)
	at javax.swing.JTextField.<init>(JTextField.java:207)
	at
javax.swing.JPasswordField.<init>(JPasswordField.java:116)
	at
javax.swing.JPasswordField.<init>(JPasswordField.java:74)
	at
sun.awt.X11.XTextFieldPeer$XAWTTextField.<init>(XTextFieldPeer.java:604)
	at
sun.awt.X11.XTextFieldPeer.<init>(XTextFieldPeer.java:59)
	at
sun.awt.X11.XToolkit.createTextField(XToolkit.java:757)
	at java.awt.TextField.addNotify(TextField.java:205)
	at java.awt.Container.addNotify(Container.java:2518)
	at java.awt.Panel.addNotify(Panel.java:71)
	at java.awt.Container.addNotify(Container.java:2518)
	at java.awt.Panel.addNotify(Panel.java:71)
	at java.awt.Container.addNotify(Container.java:2518)
	at java.awt.Panel.addNotify(Panel.java:71)
	at java.awt.Container.addNotify(Container.java:2518)
	at java.awt.Panel.addNotify(Panel.java:71)
	at java.awt.Container.addNotify(Container.java:2518)
	at java.awt.Window.addNotify(Window.java:528)
	at java.awt.Frame.addNotify(Frame.java:479)
	at java.awt.Window.show(Window.java:711)
	at
COM.sun.ir.suntea.client.SunteaApplet.a(DashoA8378)
	at b.init(DashoA8378)
	at
COM.sun.ir.suntea.client.SunteaApplet.init(DashoA8378)
	at sun.applet.AppletPanel.run(AppletPanel.java:417)
	at java.lang.Thread.run(Thread.java:626)
Execptions as followings:
java.lang.reflect.InvocationTargetException
	at java.awt.EventQueue.invokeAndWait(EventQueue.java:994)
	at MouseButtonExTest.<init>(MouseButtonExTest.java:110)
	at MouseButtonExTest.main(MouseButtonExTest.java:167)
Caused by: java.lang.NullPointerException
	at javax.swing.JPasswordField.customSetUIProperty(JPasswordField.java:337)
	at javax.swing.LookAndFeel.installProperty(LookAndFeel.java:150)
	at javax.swing.plaf.basic.BasicPasswordFieldUI.installDefaults(BasicPasswordFieldUI.java:58)
	at javax.swing.plaf.basic.BasicTextUI.installUI(BasicTextUI.java:686)
	at javax.swing.plaf.basic.BasicTextFieldUI.installUI(BasicTextFieldUI.java:57)
	at sun.awt.X11.XTextFieldPeer$AWTTextFieldUI.installUI(XTextFieldPeer.java:493)
	at javax.swing.JComponent.setUI(JComponent.java:613)
	at sun.awt.X11.XTextFieldPeer$XAWTTextField.updateUI(XTextFieldPeer.java:660)
	at javax.swing.text.JTextComponent.<init>(JTextComponent.java:305)
	at javax.swing.JTextField.<init>(JTextField.java:207)
	at javax.swing.JPasswordField.<init>(JPasswordField.java:116)
	at javax.swing.JPasswordField.<init>(JPasswordField.java:74)
	at sun.awt.X11.XTextFieldPeer$XAWTTextField.<init>(XTextFieldPeer.java:604)
	at sun.awt.X11.XTextFieldPeer.<init>(XTextFieldPeer.java:59)
	at sun.awt.X11.XToolkit.createTextField(XToolkit.java:757)
	at java.awt.TextField.addNotify(TextField.java:205)
	at java.awt.Container.addNotify(Container.java:2500)
	at java.awt.Window.addNotify(Window.java:528)
	at java.awt.Frame.addNotify(Frame.java:479)
	at java.awt.Window.show(Window.java:711)
	at java.awt.Component.show(Component.java:1406)
	at java.awt.Component.setVisible(Component.java:1359)
	at java.awt.Window.setVisible(Window.java:694)
	at MouseButtonExTest.initializeGUI(MouseButtonExTest.java:157)
	at MouseButtonExTest.access$000(MouseButtonExTest.java:14)
	at MouseButtonExTest$1.run(MouseButtonExTest.java:112)
	at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:199)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:597)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:273)
	at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:183)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:173)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:168)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:160)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:121)

Comments
EVALUATION On further discussion with AWT, we've decided it's better to add the null check to Swing. I think this should happen in BasicPasswordFieldUI.installDefaults. That is, it should check the property for null before installing it. The reason for this change of heart is that AWT has pointed out that getPropertyPrefix() is overridable, and therefore, this could easily happen to other people.
10-03-2006

EVALUATION The problem with XToolkit is as follows: we do have AWTTextFieldUI which extends MotifPasswordFieldUI. in installUI() (BasicTextFieldUI.installUI() calls BasicTextUI.installUI() which calls BasicPasswordFieldUI.installDefaults() and this method does the following: String prefix = getPropertyPrefix(); Character echoChar = (Character)UIManager.getDefaults().get(prefix + ".echoChar"); LookAndFeel.installProperty(getComponent(), "echoChar", echoChar); And it works if getPropertyPrefix() returns "PasswordField". But AWTTextFieldUI.getPropertyPrefix() usually returns "TextField" and there is no property "TextField.echoChar" :( So, we can not fix this in AWT code (except rewriting implementation of our text components which is not realistic). We either need to add "TextField.echoChar" to BasicLookAndFeel, of add null check to JPasswordField.customSetUIProperty()
10-03-2006

EVALUATION This bug results from AWT using Swing's Basic Look and Feel classes but not the Basic defaults. This is extremely fragile as Swing is free to add new properties at any time. AWT can fix this by defining the echoChar property in their custom L&F, but that's only a patch. They need to do more in order to protect from changes in Swing. Re-assigning to AWT.
09-03-2006

EVALUATION The exception is being caused by line 337 in JPasswordField: setEchoChar((Character)value); The value object is being cast to a Character and then autoboxed into a char. Thus the compiler is generating code that could throw an NPE if value is null. Probably something like ((Character)value).charValue() and then throwing the NPE. My suspicion is that the password field is being created by the Basic plaf without all of the defaults being loaded because of the funky way that the Motif AWT L&F works. The solution is to check for the null and skip this method if necessary.
09-03-2006

EVALUATION Introduced by 4985353.
03-03-2006