Ubuntu/Centos下OpenJ9 POI输出Excel的Bug
项目更换 JDK为 OpenJ9 后, 使用 POI 导出 Excel 遇到的问题
OpenJ9 版本信息
/opt/jdk/jdk-11.0.17+8/bin/java -version
openjdk version "11.0.17" 2022-10-18
IBM Semeru Runtime Open Edition 11.0.17.0 (build 11.0.17+8)
Eclipse OpenJ9 VM 11.0.17.0 (build openj9-0.35.0, JRE 11 Linux amd64-64-Bit Compressed References 20221031_559 (JIT enabled, AOT enabled)
OpenJ9 - e04a7f6c1
OMR - 85a21674f
JCL - a94c231303 based on jdk-11.0.17+8)
问题描述
使用下面的代码, 通过 SXSSFWorkbook 实例生成 2017格式的excel
public static void exportToExcel(String fileName) {
SXSSFWorkbook workbook = new SXSSFWorkbook();
Sheet sheet = workbook.createSheet("English Tab");
Row header = sheet.createRow(0);
// Styles
Font font = workbook.createFont();
font.setFontName("Arial");
font.setFontHeightInPoints((short) 12);
CellStyle cellStyle = workbook.createCellStyle();
cellStyle.setFont(font);
Cell headerCell = header.createCell(0);
headerCell.setCellValue("Name");
headerCell.setCellStyle(cellStyle);
headerCell = header.createCell(1);
headerCell.setCellValue("Age");
headerCell.setCellStyle(cellStyle);
// Row 1
Row row = sheet.createRow(1);
Cell cell = row.createCell(0);
cell.setCellValue("John Smith");
cell.setCellStyle(cellStyle);
cell = row.createCell(1);
cell.setCellValue(20);
cell.setCellStyle(cellStyle);
File currDir = new File(".");
String path = currDir.getAbsolutePath();
String fileLocation = path.substring(0, path.length() - 1) + fileName;
try (FileOutputStream outputStream = new FileOutputStream(fileLocation)) {
workbook.write(outputStream);
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
报错如下, 在 Ubuntu22.04 和 Centos7 下都会报同样的错
/opt/jdk-11.0.17+8/bin/java -jar j9test.jar
Exception in thread "main" java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:108)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:65)
Caused by: java.lang.InternalError: java.lang.reflect.InvocationTargetException
at java.desktop/sun.font.FontManagerFactory$1.run(FontManagerFactory.java:86)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:691)
at java.desktop/sun.font.FontManagerFactory.getInstance(FontManagerFactory.java:74)
at java.desktop/sun.java2d.SunGraphicsEnvironment.getFontManagerForSGE(SunGraphicsEnvironment.java:190)
at java.desktop/sun.java2d.SunGraphicsEnvironment.getAvailableFontFamilyNames(SunGraphicsEnvironment.java:224)
at java.desktop/sun.java2d.SunGraphicsEnvironment.getAvailableFontFamilyNames(SunGraphicsEnvironment.java:252)
at java.desktop/sun.java2d.HeadlessGraphicsEnvironment.getAvailableFontFamilyNames(HeadlessGraphicsEnvironment.java:75)
... 8 more
Caused by: java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
at java.desktop/sun.font.FontManagerFactory$1.run(FontManagerFactory.java:84)
... 15 more
Caused by: java.lang.NullPointerException
at java.desktop/sun.awt.FontConfiguration.getVersion(FontConfiguration.java:1264)
at java.desktop/sun.awt.FontConfiguration.readFontConfigFile(FontConfiguration.java:225)
at java.desktop/sun.awt.FontConfiguration.init(FontConfiguration.java:107)
at java.desktop/sun.awt.X11FontManager.createFontConfiguration(X11FontManager.java:719)
at java.desktop/sun.font.SunFontManager$2.run(SunFontManager.java:379)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:691)
at java.desktop/sun.font.SunFontManager.<init>(SunFontManager.java:324)
at java.desktop/sun.awt.FcFontManager.<init>(FcFontManager.java:35)
at java.desktop/sun.awt.X11FontManager.<init>(X11FontManager.java:56)
... 20 more
解决方法
对于 Ubuntu, 安装 libfontconfig1 后问题解决
sudo apt install libfontconfig1
如果没有dejavu字体, 也需要安装
sudo apt install ttf-dejavu
对于 Centos, 安装 dejavu-sans 字体和 fontconfig 后问题解决
sudo yum install dejavu-sans-fonts fontconfig
对应Centos的版本信息为
# uname -a
Linux localhost.localdomain 3.10.0-1160.49.1.el7.x86_64 #1 SMP Tue Nov 30 15:51:32 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
You have mail in /var/spool/mail/root
另一种错误 UnsatisfiedLinkError: sun/font/SunLayoutEngine.createFace
这是在几台版本较低的 Centos7 服务器上出现的, Centos版本信息为
# uname -a
Linux app02v 3.10.0-1127.19.1.el7.x86_64 #1 SMP Tue Aug 25 17:23:54 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
# uname -a
Linux bogon 3.10.0-693.el7.x86_64 #1 SMP Tue Aug 22 21:09:27 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
错误内容
Exception in thread "main" java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:108)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:65)
Caused by: java.lang.UnsatisfiedLinkError: sun/font/SunLayoutEngine.createFace(Lsun/font/Font2D;J)J
at java.desktop/sun.font.SunLayoutEngine$FaceRef.getNativePtr(SunLayoutEngine.java:202)
at java.desktop/sun.font.SunLayoutEngine.getFacePtr(SunLayoutEngine.java:162)
at java.desktop/sun.font.SunLayoutEngine.layout(SunLayoutEngine.java:170)
at java.desktop/sun.font.GlyphLayout$EngineRecord.layout(GlyphLayout.java:687)
at java.desktop/sun.font.GlyphLayout.layout(GlyphLayout.java:468)
at java.desktop/sun.font.ExtendedTextSourceLabel.createGV(ExtendedTextSourceLabel.java:329)
at java.desktop/sun.font.ExtendedTextSourceLabel.getGV(ExtendedTextSourceLabel.java:315)
at java.desktop/sun.font.ExtendedTextSourceLabel.createLogicalBounds(ExtendedTextSourceLabel.java:225)
at java.desktop/sun.font.ExtendedTextSourceLabel.getAdvance(ExtendedTextSourceLabel.java:134)
at java.desktop/java.awt.font.TextLine.init(TextLine.java:281)
at java.desktop/java.awt.font.TextLine.<init>(TextLine.java:129)
at java.desktop/java.awt.font.TextLine.fastCreateTextLine(TextLine.java:978)
at java.desktop/java.awt.font.TextLayout.fastInit(TextLayout.java:611)
at java.desktop/java.awt.font.TextLayout.<init>(TextLayout.java:532)
at org.apache.poi.ss.util.SheetUtil.getDefaultCharWidth(SheetUtil.java:301)
at org.apache.poi.xssf.streaming.AutoSizeColumnTracker.<init>(AutoSizeColumnTracker.java:117)
at org.apache.poi.xssf.streaming.SXSSFSheet.<init>(SXSSFSheet.java:95)
at org.apache.poi.xssf.streaming.SXSSFWorkbook.createAndRegisterSXSSFSheet(SXSSFWorkbook.java:726)
at org.apache.poi.xssf.streaming.SXSSFWorkbook.createSheet(SXSSFWorkbook.java:745)
... 8 more
这个错误比较奇怪, 尝试过在~/.fonts下增加字体, 以及使用 headless, 都无法解决这个问题. 但是将 SXSSFWorkbook 换成 XSSFWorkbook 就不会报错了.