CSR :
|
|
Duplicate :
|
|
Relates :
|
|
Relates :
|
|
Relates :
|
FULL PRODUCT VERSION : java version "9-ea" Java(TM) SE Runtime Environment (build 9-ea+174) Java HotSpot(TM) 64-Bit Server VM (build 9-ea+174, mixed mode) ADDITIONAL OS VERSION INFORMATION : Microsoft Windows [Version 10.0.10586] A DESCRIPTION OF THE PROBLEM : We use a customised "tri-state" checkbox. In JDK-9 a crash occurs (in LayoutFocusTraversalPolicy) when the keyboard focus moves to it by pressing the TAB key. The crash appears to have been introduced with additional logic added in JDK-9. I think the cast should be guarded with an instanceof check to match what is possible via the API of JToggleButton (and derivatives). The relevant code in LayoutFocusTraversalPolicy.accept is: } else if (aComponent instanceof JComponent) { if (SunToolkit.isInstanceOf(aComponent, "javax.swing.JToggleButton")) { JToggleButton.ToggleButtonModel model = (JToggleButton.ToggleButtonModel) ((JToggleButton) aComponent).getModel(); // <- Line 243 if (model != null) { ButtonGroup group = model.getGroup(); // <- Only use of 'model' The Tri-state check button code was taken from an old online article: http://www.javaspecialists.eu/archive/Issue082.html It's model derives directly from ButtonModel, (then delegates all method calls to a real ToggleButtonModel). The solution I imagine is to perform an instanceof check for either DefaultButtonModel or ToggleButtonModel (depending on the desired behaviour). Note that in JToggeleButton.getGroupSelection we see similar code (also added in JDK-9?) using a check-and-cast to DefaultButtonModel. Also note that while JToggleButton creates a ToggleButtonModel by default, it does not enforce it via setModel(). REGRESSION. Last worked in version 8u131 ADDITIONAL REGRESSION INFORMATION: Seems related to focus logic changes with button-groups introduced in JDK-9. For example, see 8074883 STEPS TO FOLLOW TO REPRODUCE THE PROBLEM : Execute the given code, press TAB twice and the crash should be seen ERROR MESSAGES/STACK TRACES THAT OCCUR : Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: java.desktop/javax.swing.DefaultButtonModel cannot be cast to java.desktop/javax.swing.JToggleButton$ToggleButtonModel at java.desktop/javax.swing.LayoutFocusTraversalPolicy.accept(LayoutFocusTraversalPolicy.java:243) at java.desktop/javax.swing.SortingFocusTraversalPolicy.getComponentAfter(SortingFocusTraversalPolicy.java:332) at java.desktop/javax.swing.LayoutFocusTraversalPolicy.getComponentAfter(LayoutFocusTraversalPolicy.java:107) at java.desktop/java.awt.Component.getNextFocusCandidate(Component.java:8155) at java.desktop/java.awt.Component.transferFocus(Component.java:8122) at java.desktop/java.awt.Component.nextFocus(Component.java:8115) at java.desktop/java.awt.Component.transferFocus(Component.java:8106) at java.desktop/java.awt.DefaultKeyboardFocusManager.focusNextComponent(DefaultKeyboardFocusManager.java:1403) at java.desktop/java.awt.DefaultKeyboardFocusManager.processKeyEvent(DefaultKeyboardFocusManager.java:1167) at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:4877) at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2317) at java.desktop/java.awt.Component.dispatchEvent(Component.java:4793) at java.desktop/java.awt.KeyboardFocusManager.redispatchEvent(KeyboardFocusManager.java:1950) at java.desktop/java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(DefaultKeyboardFocusManager.java:827) at java.desktop/java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(DefaultKeyboardFocusManager.java:1096) at java.desktop/java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(DefaultKeyboardFocusManager.java:966) at java.desktop/java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:792) at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:4842) at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2317) at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2758) at java.desktop/java.awt.Component.dispatchEvent(Component.java:4793) at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:761) at java.desktop/java.awt.EventQueue.access$500(EventQueue.java:97) at java.desktop/java.awt.EventQueue$3.run(EventQueue.java:712) at java.desktop/java.awt.EventQueue$3.run(EventQueue.java:706) at java.base/java.security.AccessController.doPrivileged(Native Method) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:89) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:99) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:734) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:732) at java.base/java.security.AccessController.doPrivileged(Native Method) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:89) at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:731) at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:199) at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124) at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:117) at java.desktop/java.awt.WaitDispatchSupport$2.run(WaitDispatchSupport.java:190) at java.desktop/java.awt.WaitDispatchSupport$4.run(WaitDispatchSupport.java:235) at java.desktop/java.awt.WaitDispatchSupport$4.run(WaitDispatchSupport.java:233) at java.base/java.security.AccessController.doPrivileged(Native Method) at java.desktop/java.awt.WaitDispatchSupport.enter(WaitDispatchSupport.java:233) at java.desktop/java.awt.Dialog.show(Dialog.java:1070) at java.desktop/javax.swing.JOptionPane.showOptionDialog(JOptionPane.java:876) at java.desktop/javax.swing.JOptionPane.showMessageDialog(JOptionPane.java:672) at java.desktop/javax.swing.JOptionPane.showMessageDialog(JOptionPane.java:643) at java.desktop/javax.swing.JOptionPane.showMessageDialog(JOptionPane.java:614) at snippet.Snippet.go(Snippet.java:23) at snippet.Snippet.lambda$0(Snippet.java:8) at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313) at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:759) at java.desktop/java.awt.EventQueue.access$500(EventQueue.java:97) at java.desktop/java.awt.EventQueue$3.run(EventQueue.java:712) at java.desktop/java.awt.EventQueue$3.run(EventQueue.java:706) at java.base/java.security.AccessController.doPrivileged(Native Method) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:89) at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:729) at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:199) at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124) at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101) at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90) REPRODUCIBILITY : This bug can be reproduced always. ---------- BEGIN SOURCE ---------- import java.awt.*; import javax.swing.*; public class Snippet { public static void main(String[] args) { SwingUtilities.invokeLater(() -> new Snippet().go()); } private void go() { // Non-functional model for brevity. The original, implementing // interface ButtonModel directly, can be found at: // http://www.javaspecialists.eu/archive/Issue082.html ButtonModel model = new DefaultButtonModel(); JCheckBox check = new JCheckBox("a bit broken"); check.setModel(model); JPanel panel = new JPanel(new BorderLayout()); panel.add(new JTextField("Press Tab (twice?)"), BorderLayout.NORTH); panel.add(check); JOptionPane.showMessageDialog(null, panel); System.exit(0); } } ---------- END SOURCE ---------- CUSTOMER SUBMITTED WORKAROUND : Users could click with the mouse instead of navigating via the keyboard. Programmers can move to a different tri-state checkbox implementation (from Jide, for example).
|