使用easyexcel,在服务器上报 java.lang.ArrayIndexOutOfBoundsException: 0

项目场景:

使用easyexcel,在服务器上报 java.lang.ArrayIndexOutOfBoundsException: 0

java.lang.ArrayIndexOutOfBoundsException: 0
    at sun.font.CompositeFont.getSlotFont(CompositeFont.java:351)
    at sun.font.CompositeGlyphMapper.initMapper(CompositeGlyphMapper.java:81)
    at sun.font.CompositeGlyphMapper.<init>(CompositeGlyphMapper.java:62)
    at sun.font.CompositeFont.getMapper(CompositeFont.java:409)
    at sun.font.CompositeFont.canDisplay(CompositeFont.java:435)
    at java.awt.Font.canDisplayUpTo(Font.java:2063)
    at java.awt.font.TextLayout.singleFont(TextLayout.java:470)
    at java.awt.font.TextLayout.<init>(TextLayout.java:531)
    at org.apache.poi.ss.util.SheetUtil.getDefaultCharWidth(SheetUtil.java:275)
    at org.apache.poi.xssf.streaming.AutoSizeColumnTracker.<init>(AutoSizeColumnTracker.java:117)
    at org.apache.poi.xssf.streaming.SXSSFSheet.<init>(SXSSFSheet.java:82)
    at org.apache.poi.xssf.streaming.SXSSFWorkbook.createAndRegisterSXSSFSheet(SXSSFWorkbook.java:658)
    at org.apache.poi.xssf.streaming.SXSSFWorkbook.createSheet(SXSSFWorkbook.java:679)
    at org.apache.poi.xssf.streaming.SXSSFWorkbook.createSheet(SXSSFWorkbook.java:90)
    at com.alibaba.excel.util.WorkBookUtil.createSheet(WorkBookUtil.java:66)

问题描述:

在本地测试Excel的导出是正常的,但是上传了服务器,通过Postman 测试发现了返回500,服务器报错


原因分析:

经过 远程链接服务器的Java程序 Debug 到 报错列表中的 :at sun.font.CompositeFont.getSlotFont(CompositeFont.java:351) 位置
使用easyexcel,在服务器上报 java.lang.ArrayIndexOutOfBoundsException: 0_第1张图片

根据Debug的提示判断是由 deferredInitialisation[slot] 引起的报错,Debug显示 deferredInitialisation 长度为 0slot指为0

做个校验:
使用easyexcel,在服务器上报 java.lang.ArrayIndexOutOfBoundsException: 0_第2张图片

接下来让我们看看 deferredInitialisation这个数组的由来:

菜鸡的我 进过了一天的Debug 和 踩坑 终于是Debug到了,下面说重要的地方~~

1、java.awt.Font#getFont2D
private Font2D getFont2D() {
	// 用于检索当前平台的有效 FontManager 实例的工厂类。为 Linux、Solaris 和 Windows 提供了默认实现。
    FontManager fm = FontManagerFactory.getInstance(); // 从此处进入
    if (fm.usingPerAppContextComposites() &&
        font2DHandle != null &&
        font2DHandle.font2D instanceof CompositeFont &&
        ((CompositeFont)(font2DHandle.font2D)).isStdComposite()) {
        return fm.findFont2D(name, style,
                                      FontManager.LOGICAL_FALLBACK);
    } else if (font2DHandle == null) {
        font2DHandle =
            fm.findFont2D(name, style,
                          FontManager.LOGICAL_FALLBACK).handle;
    }
    /* Do not cache the de-referenced font2D. It must be explicitly
     * de-referenced to pick up a valid font in the event that the
     * original one is marked invalid
     */
    return font2DHandle.font2D;
}
2、sun/font/FontManagerFactory.java (优先执行静态代码块)
static {
	// 根据不同操作系统加载不同的 FontManager
    if (FontUtilities.isWindows) {
        DEFAULT_CLASS = "sun.awt.Win32FontManager";
    } else if (FontUtilities.isMacOSX) {
        DEFAULT_CLASS = "sun.font.CFontManager";
        } else {
        DEFAULT_CLASS = "sun.awt.X11FontManager";
        }
}
3、sun.font.FontManager#getInstance()
/**
 * Get a valid FontManager implementation for the current platform.
 *
 * @return a valid FontManager instance for the current platform
 */
public static synchronized FontManager getInstance() {

    if (instance != null) {
        return instance;
    }

    AccessController.doPrivileged(new PrivilegedAction<Object>() {

        public Object run() {
            try {
                String fmClassName =
                        System.getProperty("sun.font.fontmanager",
                                           DEFAULT_CLASS);
                ClassLoader cl = ClassLoader.getSystemClassLoader();
                // 注册 通过静态代码块得到的 FontManager 看 步骤 4
                Class<?> fmClass = Class.forName(fmClassName, true, cl);
                // 通过静态代码块得到的 FontManager,反射创建对象 
                instance =
                   (FontManager) fmClass.getDeclaredConstructor().newInstance();
            } catch (ReflectiveOperationException ex) {
                throw new InternalError(ex);

            }
            return null;
        }
    });

    return instance;
}

由于在远程Debug找到了原因,切远程Debug与本地代码经常对应不上,换至Windows上进行Debug
故步骤 3 创建的FontManagerWin32FontManager

4、sun.awt.Win32FontManager(先执行静态代码块)
static {
	AccessController.doPrivileged(new PrivilegedAction<Object>() {
		public Object run() {
      		// 获取 EUDC 字体文件
			String eudcFile = getEUDCFontFile();
			if (eudcFile != null) {
			    try {
			        /* Must use Java rasteriser since GDI doesn't
			         * enumerate (allow direct use) of EUDC fonts.
			         */
			        eudcFont = new TrueTypeFont(eudcFile, null, 0,
			                                    true, false);
			    } catch (FontFormatException e) {
			    }
			}
			return null;
		}
  });
}
5、sun.font.SunFontManager#SunFontManager()
protected SunFontManager() {
	// 这里就是加载系统字体的地方
    this.initJREFontMap();
    AccessController.doPrivileged(new PrivilegedAction() {
        public Object run() {
            File var1 = new File(SunFontManager.jreFontDirName + File.separator + "badfonts.txt");
            String var5;
            if (var1.exists()) {
                FileInputStream var2 = null;

                try {
                    SunFontManager.this.badFonts = new ArrayList();
                    var2 = new FileInputStream(var1);
                    InputStreamReader var3 = new InputStreamReader(var2);
                    BufferedReader var4 = new BufferedReader(var3);

                    while(true) {
                        var5 = var4.readLine();
                        if (var5 == null) {
                            break;
                        }

                        if (FontUtilities.debugFonts()) {
                            FontUtilities.getLogger().warning("read bad font: " + var5);
                        }

                        SunFontManager.this.badFonts.add(var5);
                    }
                } catch (IOException var8) {
                    try {
                        if (var2 != null) {
                            var2.close();
                        }
                    } catch (IOException var7) {
                    }
                }
            }

            if (FontUtilities.isLinux) {
                SunFontManager.this.registerFontDir(SunFontManager.jreFontDirName);
            }

            SunFontManager.this.registerFontsInDir(SunFontManager.jreFontDirName, true, 2, true, false);
            SunFontManager.this.fontConfig = SunFontManager.this.createFontConfiguration();
            if (SunFontManager.isOpenJDK()) {
                String[] var9 = SunFontManager.this.getDefaultPlatformFont();
                SunFontManager.this.defaultFontName = var9[0];
                SunFontManager.this.defaultFontFileName = var9[1];
            }

            String var10 = SunFontManager.this.fontConfig.getExtraFontPath();
            boolean var11 = false;
            boolean var12 = false;
            var5 = System.getProperty("sun.java2d.fontpath");
            if (var5 != null) {
                if (var5.startsWith("prepend:")) {
                    var11 = true;
                    var5 = var5.substring("prepend:".length());
                } else if (var5.startsWith("append:")) {
                    var12 = true;
                    var5 = var5.substring("append:".length());
                }
            }

            if (FontUtilities.debugFonts()) {
                PlatformLogger var6 = FontUtilities.getLogger();
                var6.info("JRE font directory: " + SunFontManager.jreFontDirName);
                var6.info("Extra font path: " + var10);
                var6.info("Debug font path: " + var5);
            }

            if (var5 != null) {
                SunFontManager.this.fontPath = SunFontManager.this.getPlatformFontPath(SunFontManager.noType1Font);
                if (var10 != null) {
                    SunFontManager.this.fontPath = var10 + File.pathSeparator + SunFontManager.this.fontPath;
                }

                if (var12) {
                    SunFontManager.this.fontPath = SunFontManager.this.fontPath + File.pathSeparator + var5;
                } else if (var11) {
                    SunFontManager.this.fontPath = var5 + File.pathSeparator + SunFontManager.this.fontPath;
                } else {
                    SunFontManager.this.fontPath = var5;
                }

                SunFontManager.this.registerFontDirs(SunFontManager.this.fontPath);
            } else if (var10 != null) {
                SunFontManager.this.registerFontDirs(var10);
            }

            if (FontUtilities.isSolaris && Locale.JAPAN.equals(Locale.getDefault())) {
                SunFontManager.this.registerFontDir("/usr/openwin/lib/locale/ja/X11/fonts/TT");
            }
			
			// 初始化 CompositeFont
            SunFontManager.this.initCompositeFonts(SunFontManager.this.fontConfig, (ConcurrentHashMap)null);
            return null;
        }
    });
    boolean var1 = (Boolean)AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
        public Boolean run() {
            String var1 = System.getProperty("java2d.font.usePlatformFont");
            String var2 = System.getenv("JAVA2D_USEPLATFORMFONT");
            return "true".equals(var1) || var2 != null;
        }
    });
    if (var1) {
        this.usePlatformFontMetrics = true;
        System.out.println("Enabling platform font metrics for win32. This is an unsupported option.");
        System.out.println("This yields incorrect composite font metrics as reported by 1.1.x releases.");
        System.out.println("It is appropriate only for use by applications which do not use any Java 2");
        System.out.println("functionality. This property will be removed in a later release.");
    }

}
6、sun.font.SunFontManager#registerCompositeFont()
protected void registerCompositeFont(String var1, String[] var2, String[] var3, int var4, int[] var5, int[] var6, boolean var7) {
   CompositeFont var8 = new CompositeFont(var1, var2, var3, var4, var5, var6, var7, this);
    this.addCompositeToFontList(var8, 2);
    synchronized(this.compFonts) {
        this.compFonts[this.maxCompFont++] = var8;
    }
}
7、sun.font.CompositeFont#CompositeFont()
public CompositeFont(String name, String[] compFileNames,
                         String[] compNames, int metricsSlotCnt,
                         int[] exclRanges, int[] maxIndexes,
                         boolean defer, SunFontManager fm) {

    handle = new Font2DHandle(this);
    fullName = name;
    componentFileNames = compFileNames;
    componentNames = compNames;
    if (compNames == null) {
        numSlots = componentFileNames.length;
    } else {
        numSlots = componentNames.length;
    }
    
     numSlots = (numSlots <= 254) ? numSlots : 254;

    numMetricsSlots = metricsSlotCnt;
    exclusionRanges = exclRanges;
    maxIndices = maxIndexes;

    if (fm.getEUDCFont() != null) {
        int msCnt = numMetricsSlots;
        int fbCnt = numSlots - msCnt;
        numSlots++;
        if (componentNames != null) {
            componentNames = new String[numSlots];
            System.arraycopy(compNames, 0, componentNames, 0, msCnt);
            componentNames[msCnt] = fm.getEUDCFont().getFontName(null);
            System.arraycopy(compNames, msCnt,
                             componentNames, msCnt+1, fbCnt);
        }
        if (componentFileNames != null) {
            componentFileNames = new String[numSlots];
            System.arraycopy(compFileNames, 0,
                              componentFileNames, 0, msCnt);
            System.arraycopy(compFileNames, msCnt,
                              componentFileNames, msCnt+1, fbCnt);
        }
        components = new PhysicalFont[numSlots];
        components[msCnt] = fm.getEUDCFont();
        // 此时已经找到了 那个导致抛出异常数组的赋值
        deferredInitialisation = new boolean[numSlots];
        if (defer) {
            for (int i=0; i<numSlots-1; i++) {
                deferredInitialisation[i] = true;
            }
        }
    } else {
        components = new PhysicalFont[numSlots];
        deferredInitialisation = new boolean[numSlots];
        if (defer) {
            for (int i=0; i<numSlots; i++) {
                deferredInitialisation[i] = true;
            }
        }
    }

    fontRank = Font2D.FONT_CONFIG_RANK;

    int index = fullName.indexOf('.');
    if (index>0) {
        familyName = fullName.substring(0, index);
        
        if (index+1 < fullName.length()) {
            String styleStr = fullName.substring(index+1);
            if ("plain".equals(styleStr)) {
                style = Font.PLAIN;
            } else if ("bold".equals(styleStr)) {
                style = Font.BOLD;
            } else if ("italic".equals(styleStr)) {
                style = Font.ITALIC;
            } else if ("bolditalic".equals(styleStr)) {
                style = Font.BOLD | Font.ITALIC;
            }
        }
    } else {
        familyName = fullName;
    }
}

解决方案:

使用Root权限启动
给服务器添加字体:
1、查看中文字体
fc-list :lang=zh
2、安装字体
yum -y install fontconfig	#安装字体库
yum -y install ttmkfdir	mkfontscale	#安装字体索引信息

可拷贝Windows的字体目录:C:\Windows\Fonts

3、linux字体目录:/usr/share/fonts,建议创建一个目录mkdir chinese 放中文字体
4、把字体上传到/usr/share/fonts/chinese目录
5、然后在/usr/share/fonts/chinese执行命令,生成字库索引信息
mkfontscale
mkfontdir
6、更新字体缓存
fc-cache

你可能感兴趣的:(遇到的BUG问题,java)