使用XDocReport转换ODT到PDF时出现NewSubrsIndexNonCID空指针异常
使用XDocReport转换ODT到PDF时的NullPointerException问题
依赖配置
<dependency> <groupId>fr.opensagres.xdocreport</groupId> <artifactId>xdocreport</artifactId> <version>2.0.4</version> </dependency> <!-- PDF转换依赖 --> <dependency> <groupId>fr.opensagres.xdocreport</groupId> <artifactId>fr.opensagres.poi.xwpf.converter.pdf</artifactId> <version>2.0.4</version> </dependency>
代码实现
ITemplateEngine templateEngine = VelocityTemplateEngine.getDefault(); InputStream in= new FileInputStream(new File("ODTHelloWordWithVelocity.odt")); IXDocReport report = XDocReportRegistry.getRegistry().loadReport(in,templateEngine); // 创建Java模型上下文 IContext context = report.createContext(); context.put("name", "world"); // 设置PDF转换格式 Options options = Options.getTo(ConverterTypeTo.PDF); // 合并模型并转换为PDF OutputStream out = new FileOutputStream(new File("ODTHelloWordWithVelocity_Out.odt")); report.convert(context, options, out);
错误信息
执行代码后抛出异常:
com.lowagie.text.ExceptionConverter: Cannot read the array length because "this.NewSubrsIndexNonCID" is null
更新后的完整堆栈跟踪:
2023-08-29T18:11:38.381+03:00 ERROR 13480 --- [nio-8080-exec-3] f.o.x.c.d.p.i.XWPF2PDFViaITextConverter : java.lang.NullPointerException: Cannot read the array length because "this.NewSubrsIndexNonCID" is null 2023-08-29T18:11:38.385+03:00 ERROR 13480 --- [nio-8080-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: java.lang.RuntimeException: fr.opensagres.xdocreport.converter.XDocConverterException: fr.opensagres.poi.xwpf.converter.core.XWPFConverterException: java.lang.NullPointerException: Cannot read the array length because "this.NewSubrsIndexNonCID" is null] with root cause com.lowagie.text.ExceptionConverter: Cannot read the array length because "this.NewSubrsIndexNonCID" is null
已尝试的解决方法
发现使用Calibri字体时转换正常,推测是字体问题,尝试通过以下代码注册自定义字体,但问题依旧:
@PostConstruct public void init() { var fonts = resourceLoader.getResources("classpath:fonts/*"); for (var font : fonts) { FontFactory.register(font.getURL().toString()); } }
核心疑问与需求
NewSubrsIndexNonCID是什么?- 如何修复该异常?
- 此前用Doc4j可正常转换但速度极慢(4页文档需5秒以上),希望通过XDocReport实现高效转换。
解决方案
关于NewSubrsIndexNonCID
这是XDocReport底层依赖的iText库中,处理非CID(字符识别)字体子集化时的核心数组变量,用于存储字体子表的索引信息。当字体文件损坏、不完整,或iText无法正确解析字体的子集元数据时,该变量会被置为null,触发空指针异常。
修复步骤
替换文档中的问题字体
打开源ODT文档,将所有特殊字体、非系统兼容字体替换为Calibri、Arial等iText能稳定解析的通用字体。确保文档未使用损坏、未嵌入或罕见的字体类型。修正字体注册逻辑
原代码仅注册到iText的FontFactory,未同步到XDocReport的字体注册表,导致转换时无法正确匹配字体。调整注册逻辑如下:@PostConstruct public void initFonts() throws Exception { Resource[] fontResources = resourceLoader.getResources("classpath:fonts/*"); FontRegistry xdocFontRegistry = FontRegistry.getRegistry(); for (Resource font : fontResources) { // 注册到XDocReport字体注册表 xdocFontRegistry.registerFont(font.getInputStream()); // 同步注册到iText FontFactory FontFactory.register(font.getURL().toString()); } }同时在转换时添加字体 fallback 逻辑,避免因字体匹配失败触发异常:
Options options = Options.getTo(ConverterTypeTo.PDF) .subOptions(ConverterTypeTo.PDF.getSubOptionsBuilder() .fontProvider(new FontProvider() { @Override public Font getFont(String fontName, String encoding, boolean embedded, float size, int style, BaseColor color) { try { return FontFactory.getFont(fontName, encoding, embedded, size, style, color); } catch (Exception e) { // fallback到已知兼容的Calibri字体 return FontFactory.getFont("Calibri", encoding, embedded, size, style, color); } } }) .build());升级依赖版本
XDocReport 2.0.4依赖的iText版本存在字体解析的已知bug,升级到最新稳定版(如2.0.5)可修复部分兼容性问题:<dependency> <groupId>fr.opensagres.xdocreport</groupId> <artifactId>xdocreport</artifactId> <version>2.0.5</version> </dependency> <dependency> <groupId>fr.opensagres.xdocreport</groupId> <artifactId>fr.opensagres.poi.xwpf.converter.pdf</artifactId> <version>2.0.5</version> </dependency>确保文档嵌入字体
在LibreOffice/OpenOffice中打开ODT文档,通过文件 -> 属性 -> 字体检查所有使用的字体是否已嵌入到文档中,避免转换时依赖系统缺失的字体。
内容的提问来源于stack exchange,提问作者JavaDevS
相关产品推荐
相关产品推荐

