-
Bug
-
Resolution: Fixed
-
P3
-
9
-
b23
-
x86
-
generic
Issue | Fix Version | Assignee | Priority | Status | Resolution | Resolved In Build |
---|---|---|---|---|---|---|
JDK-8337619 | openjdk8u432 | Kazuhisa Takakuri | P3 | Open | Unresolved | |
JDK-8277484 | 8u331 | Alexey Ivanov | P3 | Resolved | Fixed | b01 |
JDK-8277732 | 8u321 | Alexey Ivanov | P3 | Resolved | Fixed | b06 |
JDK-8278315 | 8u311 | Alexey Ivanov | P3 | Closed | Fixed | b34 |
JDK-8277575 | 7u341 | Alexey Ivanov | P3 | Resolved | Fixed | b01 |
JDK-8277723 | 7u331 | Alexey Ivanov | P3 | Resolved | Fixed | b06 |
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).
- backported by
-
JDK-8337619 Exception when Tab key moves focus to a JCheckbox with a custom ButtonModel
- Open
-
JDK-8277484 Exception when Tab key moves focus to a JCheckbox with a custom ButtonModel
- Resolved
-
JDK-8277575 Exception when Tab key moves focus to a JCheckbox with a custom ButtonModel
- Resolved
-
JDK-8277723 Exception when Tab key moves focus to a JCheckbox with a custom ButtonModel
- Resolved
-
JDK-8277732 Exception when Tab key moves focus to a JCheckbox with a custom ButtonModel
- Resolved
-
JDK-8278315 Exception when Tab key moves focus to a JCheckbox with a custom ButtonModel
- Closed
- csr for
-
JDK-8182695 Exception when Tab key moves focus to a JCheckbox with a custom ButtonModel
- Closed
- duplicates
-
JDK-8276986 Cannot be cast to javax.swing.JToggleButton$ToggleButtonModel in 8u311
- Closed
- relates to
-
JDK-8277243 Cast to DefaultButtonModel to access getGroup() is unnecessary
- Open
-
JDK-8277202 Create a test to cover independent ButtonModel implementation for JToggleButton
- Open
-
JDK-8154043 Fields not reachable anymore by tab-key, because of new tabbing behaviour of radio button groups.
- Resolved
- links to
-
Review(master) openjdk/jdk8u-dev/285