【问题标题】:JRE bug? JTable contains certain string -> ArrayIndexOutOfBoundsExceptionJRE错误? JTable 包含某些字符串 -> ArrayIndexOutOfBoundsException
【发布时间】:2014-01-30 11:57:56
【问题描述】:

一位用户报告说某个YouTube video 导致我们的程序失败。经过调查,似乎将包含该视频标题的字符串添加到 JTable 会导致渲染代码中某处出现 ArrayIndexOutOfBoundsException。

我们已在 Windows XP、7 和 8 以及 Ubuntu 上的 Java 7u45 和 Java 8 (b121) 上测试并确认了这一点。

这是一个演示该问题的测试程序:

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;
    }
}

每次 Swing 尝试渲染文本时,此堆栈跟踪都会打印到 stderr:

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)

你能重现这个吗?字符串中的什么特性实际上导致了这种情况?它真的是一个 JRE 错误吗?我应该向 Oracle 报告吗?

【问题讨论】:

  • 这可能是一个 JDK 错误。 Looking at the code 它似乎正在构建一个边界框,因此字体返回的其中一个字形可能不起作用(可能是一种坏字体,但 Swing 应该补偿)。为了缩小范围,我建议逐步从测试字符串中删除单个字符代码的所有实例(例如,删除所有 \u0D02,然后删除所有 \u0D15 等等......其中有 23 个)。跨度>
  • 另外,我会在JTable 中添加一个简单的 ASCII 列标签。没关系,但最好消除零长度字符串的可能性。
  • 他们已经知道了。请参阅bugs.sun.com/bugdatabase/…bugs.sun.com/bugdatabase/view_bug.do?bug_id=5004101——据称已修复,但显然没有。错误报告可能会为您提供更多信息。
  • @kdgregory JDK-6374477 确实看起来非常相似,但它并没有修复。该报告来自 2006 年。:(

标签: java swing unicode crash fatal-error


【解决方案1】:

该错误已于 2014 年 1 月报告给 Oracle,三个月后它以 JDK-8041480 出现在公共错误跟踪器中。该错误已于 2016 年 9 月针对 Java 9 修复。

【讨论】:

    【解决方案2】:

    我们在使用 Code2000.ttf 呈现马拉雅拉姆语菜单条目时遇到了类似的问题。

    线程“AWT-EventQueue-0”中的异常 java.lang.ArrayIndexOutOfBoundsException:280 在 sun.font.ExtendedTextSourceLabel.createCharinfo(ExtendedTextSourceLabel.java:814) 在 sun.font.ExtendedTextSourceLabel.getCharinfo(ExtendedTextSourceLabel.java:548) 在 sun.font.ExtendedTextSourceLabel.getCharX(ExtendedTextSourceLabel.java:357)

    最终我们发现菜单项名称有尾随空格。删除这些为我们解决了这个问题。

    ..ede

    【讨论】:

      【解决方案3】:

      我们已经在 J​​ava 7u45 和 Java 8 (b121) 上测试并确认了这一点 在 Windows XP、7 和 8 以及 Ubuntu 上。

      JRE 错误?


      编辑这是 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();
                  }
              });
          }
      }
      

      生成异常

      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 其他 JComponents(减少了一部分,可以忽略这个字符序列,但可能我没有使用正确的字体),但在此代码示例中使用了 Renderers 概念

      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;
              }
          }
      }
      

      【讨论】:

      • 请致电Font.. :)
      • mKorbel, @AndrewThompson, 进一步测试表明,如果“Arial Unicode MS”字体仅安装在计算机上(无论哪种字体实际上是使用 setFont(...)) 设置的。此字体随 Microsoft Office 提供,默认情况下不包含在 Windows 中。
      • @ntoskrnl 呵呵。这很有趣,是的,我确实安装了 Font(和 MS Office)。
      猜你喜欢
      • 1970-01-01
      • 2016-08-09
      • 2020-05-01
      • 2014-05-07
      • 1970-01-01
      • 2011-03-31
      • 2018-05-01
      • 2015-03-15
      相关资源
      最近更新 更多