A user reported that a certain YouTube video causes our program to fail. Upon investigation it seems that adding a String containing the title of that video to a JTable causes an ArrayIndexOutOfBoundsException somewhere in the rendering code.
We have tested and confirmed this on both Java 7u45 and Java 8 (b121) on Windows XP, 7 and 8, and Ubuntu.
Here is a test program demonstrating the issue:
import javax.swing.*;
import java.awt.*;
public class TestJTableAIOOBE {
private static final String TEXT = "\u0D38\u0D4D\u0D31\u0D4D\u0D31\u0D40\u0D32\u0D4D\u200D \u0D15\u0D31\u0D3F\u0D15\u0D4D\u0D15\u0D24\u0D4D\u0D24\u0D3F\u0D2F\u0D3F\u0D32\u0D4D\u200D \u0D2F\u0D47\u0D36\u0D41\u0D15\u0D4D\u0D30\u0D3F\u0D38\u0D4D\u0D24\u0D41\u0D35\u0D3F\u0D28\u0D4D\u0D31\u0D46 \u0D30\u0D42\u0D2A\u0D02 \u0D2A\u0D4D\u0D30\u0D24\u0D4D\u0D2F\u0D15\u0D4D\u0D37\u0D2A\u0D4D\u0D2A\u0D46\u0D1F\u0D4D\u0D1F\u0D41";
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
Font font = findFont();
if (font == null) {
System.out.println("No suitable font found");
return;
}
System.out.println("Using font: " + font);
JTable table = new JTable(new Object[][]{{TEXT}}, new Object[]{"title"});
table.setFont(font);
JFrame frame = new JFrame();
frame.add(table);
frame.pack();
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.setVisible(true);
}
});
}
private static Font findFont() {
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
for (Font font : ge.getAllFonts()) {
if (font.canDisplayUpTo(TEXT) == -1) {
return font.deriveFont(0, 12);
}
}
return null;
}
}
This stack trace is printed to stderr every time Swing attempts to render the text:
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 48
at sun.font.ExtendedTextSourceLabel.createCharinfo(ExtendedTextSourceLabel.java:814)
at sun.font.ExtendedTextSourceLabel.getCharinfo(ExtendedTextSourceLabel.java:548)
at sun.font.ExtendedTextSourceLabel.getLineBreakIndex(ExtendedTextSourceLabel.java:480)
at java.awt.font.TextMeasurer.calcLineBreak(TextMeasurer.java:330)
at java.awt.font.TextMeasurer.getLineBreakIndex(TextMeasurer.java:566)
at java.awt.font.LineBreakMeasurer.nextOffset(LineBreakMeasurer.java:359)
at java.awt.font.LineBreakMeasurer.nextOffset(LineBreakMeasurer.java:328)
at sun.swing.SwingUtilities2.clipString(SwingUtilities2.java:472)
at javax.swing.SwingUtilities.layoutCompoundLabelImpl(SwingUtilities.java:1023)
at javax.swing.SwingUtilities.layoutCompoundLabel(SwingUtilities.java:892)
at javax.swing.plaf.basic.BasicLabelUI.layoutCL(BasicLabelUI.java:94)
at javax.swing.plaf.basic.BasicLabelUI.layout(BasicLabelUI.java:201)
at javax.swing.plaf.basic.BasicLabelUI.paint(BasicLabelUI.java:164)
at javax.swing.plaf.ComponentUI.update(ComponentUI.java:161)
at javax.swing.JComponent.paintComponent(JComponent.java:777)
at javax.swing.JComponent.paint(JComponent.java:1053)
at javax.swing.CellRendererPane.paintComponent(CellRendererPane.java:151)
at javax.swing.plaf.basic.BasicTableUI.paintCell(BasicTableUI.java:2115)
at javax.swing.plaf.basic.BasicTableUI.paintCells(BasicTableUI.java:2016)
at javax.swing.plaf.basic.BasicTableUI.paint(BasicTableUI.java:1812)
at javax.swing.plaf.ComponentUI.update(ComponentUI.java:161)
at javax.swing.JComponent.paintComponent(JComponent.java:777)
at javax.swing.JComponent.paint(JComponent.java:1053)
at javax.swing.JComponent.paintChildren(JComponent.java:886)
at javax.swing.JComponent.paint(JComponent.java:1062)
at javax.swing.JComponent.paintChildren(JComponent.java:886)
at javax.swing.JComponent.paint(JComponent.java:1062)
at javax.swing.JLayeredPane.paint(JLayeredPane.java:586)
at javax.swing.JComponent.paintChildren(JComponent.java:886)
at javax.swing.JComponent.paintToOffscreen(JComponent.java:5224)
at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1532)
at javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1455)
at javax.swing.RepaintManager.paint(RepaintManager.java:1252)
at javax.swing.JComponent.paint(JComponent.java:1039)
at java.awt.GraphicsCallback$PaintCallback.run(GraphicsCallback.java:39)
at sun.awt.SunGraphicsCallback.runOneComponent(SunGraphicsCallback.java:79)
at sun.awt.SunGraphicsCallback.runComponents(SunGraphicsCallback.java:116)
at java.awt.Container.paint(Container.java:1973)
at java.awt.Window.paint(Window.java:3901)
at javax.swing.RepaintManager$3.run(RepaintManager.java:822)
at javax.swing.RepaintManager$3.run(RepaintManager.java:794)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:75)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:794)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:769)
at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:718)
at javax.swing.RepaintManager.access$1100(RepaintManager.java:62)
at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1680)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:744)
at java.awt.EventQueue.access$400(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:697)
at java.awt.EventQueue$3.run(EventQueue.java:691)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:75)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:714)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
Can you reproduce this? What peculiarity in the string actually causes this? Is it really a JRE bug? Should I report it to Oracle?
The bug was reported to Oracle in January 2014, and three months later it appeared in the public bug tracker as JDK-8041480. The bug was fixed for Java 9 in September 2016.
We have tested and confirmed this on both Java 7u45 and Java 8 (b121) on Windows XP, 7 and 8, and Ubuntu.
and
JRE bug?
\u200D - ZERO WIDTH JOINER
(hint 2times in String)EDIT this is is Font issue (used) for JTable
.
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
public class Test {
private String TEXT = "Jesus appear in Knife \u0D38\u0D4D\u0D31\u0D4D\u0D31\u0D40"
+ "\u0D32\u0D4D\u0D4D\u0D15\u0D31\u0D3F\u0D15\u0D4D\u0D15\u0D24\u0D4D\u0D24\u0D3F\u0D2F"
+ "\u0D3F\u0D32\u0D4D\u0D15\u0D2F\u0D47\u0D36\u0D41\u0D15\u0D4D\u0D30\u0D3F\u0D38\u0D4D"
+ "\u0D24\u0D41\u0D35\u0D3F\u0D28\u0D4D\u0D31\u0D46 \u0D30\u0D42\u0D2A\u0D02\u0D2A\u0D4D"
+ "\u0D30\u0D24\u0D4D\u0D2F\u0D15\u0D4D\u0D37\u0D2A\u0D4D\u0D2A\u0D46\u0D1F\u0D4D\u0D1F\u0D41";
private String _TEXT = "Jesus appear in Knife \u0D38\u0D4D\u0D31\u0D4D\u0D31\u0D40\u0D32\u0D4D\u200D "
+ "\u0D15\u0D31\u0D3F\u0D15\u0D4D\u0D15\u0D24\u0D4D\u0D24\u0D3F\u0D2F\u0D3F\u0D32\u0D4D"
+ "\u200D \u0D2F\u0D47\u0D36\u0D41\u0D15\u0D4D\u0D30\u0D3F\u0D38\u0D4D\u0D24\u0D41\u0D35"
+ "\u0D3F\u0D28\u0D4D\u0D31\u0D46 \u0D30\u0D42\u0D2A\u0D02 \u0D2A\u0D4D\u0D30\u0D24\u0D4D"
+ "\u0D2F\u0D15\u0D4D\u0D37\u0D2A\u0D4D\u0D2A\u0D46\u0D1F\u0D4D\u0D1F\u0D41";
private JTable table;
DefaultTableModel model = new DefaultTableModel(
new Object[][]{{_TEXT},},
new String[]{"Col 1",});
public Test() {
table.setFont(new java.awt.Font("Tahoma", 1, 21));
table = new JTable(model);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(table);
frame.pack();
frame.setVisible(true);
}
//http://stackoverflow.com/questions/21062484/jre-bug-jtable-contains-certain-string-arrayindexoutofboundsexception
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new Test();
}
});
}
}
with generated exception
run:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at Bugs.Test.<init>(Test.java:28)
at Bugs.Test$1.run(Test.java:42)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:251)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:733)
at java.awt.EventQueue.access$200(EventQueue.java:103)
at java.awt.EventQueue$3.run(EventQueue.java:694)
at java.awt.EventQueue$3.run(EventQueue.java:692)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:703)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)
BUILD SUCCESSFUL (total time: 1 second)
EDIT_2 other JComponents (reduced part of, pretty to ignore this chars sequence, but maybe I'm not used proper Font), but Renderers concept is used in this code example
import java.awt.*;
import java.awt.event.*;
import java.util.Locale;
import javax.swing.*;
import javax.swing.plaf.FontUIResource;
import javax.swing.plaf.basic.BasicComboBoxRenderer;
import javax.swing.table.DefaultTableModel;
public class SystemFontDisplayer extends JFrame {
private static final long serialVersionUID = 1L;
private JFrame frame = new JFrame("Nimbus UIDeafaults and Font");
private JComboBox fontsBox;
private javax.swing.Timer timer = null;
private String buggyConstalation = "Jesus appear in Knife \u0D38\u0D4D"
+ "\u0D31\u0D4D\u0D31\u0D40\u0D32\u0D4D\u200D\u0D15\u0D31\u0D3F"
+ "\u0D15\u0D4D\u0D15\u0D24\u0D4D\u0D24\u0D3F\u0D2F\u0D3F\u0D32"
+ "\u0D4D\u200D \u0D2F\u0D47\u0D36\u0D41\u0D15\u0D4D\u0D30\u0D3F"
+ "\u0D38\u0D4D\u0D24\u0D41\u0D35\u0D3F\u0D28\u0D4D\u0D31\u0D46"
+ "\u0D30\u0D42\u0D2A\u0D02 \u0D2A\u0D4D\u0D30\u0D24\u0D4D\u0D2F"
+ "\u0D15\u0D4D\u0D37\u0D2A\u0D4D\u0D2A\u0D46\u0D1F\u0D4D\u0D1F\u0D41";
private JButton testButton = new JButton(buggyConstalation);
private JTextField testTextField = new JTextField(buggyConstalation);
private JLabel testLabel = new JLabel(buggyConstalation);//caused by \u200D
private JTable table;
private DefaultTableModel model;
public SystemFontDisplayer() {
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
String[] fontFamilyNames = ge.getAvailableFontFamilyNames(Locale.getDefault());
fontsBox = new JComboBox(fontFamilyNames);
fontsBox.setSelectedItem("SansSerif");
fontsBox.setRenderer(new ComboRenderer());
fontsBox.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
final String fontName = fontsBox.getSelectedItem().toString();
fontsBox.setFont(new Font(fontName, Font.PLAIN, 16));
start();
}
}
});
fontsBox.setSelectedItem(0);
fontsBox.getEditor().selectAll();
model = new DefaultTableModel(
new Object[][]{{buggyConstalation,buggyConstalation},},
new String[]{"Col 1","Col 2",});
table = new JTable(model);
frame.setLayout(new GridLayout(5, 0, 20, 20));
frame.add(fontsBox);
frame.add(testButton);
frame.add(testTextField);
frame.add(testLabel);
frame.add(table);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocation(200, 105);
frame.pack();
java.awt.EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
fontsBox.setPopupVisible(true);
fontsBox.setPopupVisible(false);
}
});
frame.setVisible(true);
}
private void start() {
timer = new javax.swing.Timer(750, updateCol());
timer.setRepeats(false);
timer.start();
}
public Action updateCol() {
return new AbstractAction("text load action") {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
final Font fnt = new Font(fontsBox.getSelectedItem().toString(), Font.PLAIN, 12);
final FontUIResource res = new FontUIResource(fnt);
UIManager.getLookAndFeelDefaults().put("Button.font", res);
UIManager.getLookAndFeelDefaults().put("TextField.font", res);
UIManager.getLookAndFeelDefaults().put("Label.font", res);
UIManager.getLookAndFeelDefaults().put("Table.font", res);
SwingUtilities.updateComponentTreeUI(frame);
}
};
}
public static void main(String arg[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
SystemFontDisplayer systemFontDisplayer = new SystemFontDisplayer();
}
});
}
private class ComboRenderer extends BasicComboBoxRenderer {
private static final long serialVersionUID = 1L;
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
final Object fntObj = value;
final String fontFamilyName = (String) fntObj;
setFont(new Font(fontFamilyName, Font.PLAIN, 16));
return this;
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With