You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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());
    }
}

核心疑问与需求

  1. NewSubrsIndexNonCID是什么?
  2. 如何修复该异常?
  3. 此前用Doc4j可正常转换但速度极慢(4页文档需5秒以上),希望通过XDocReport实现高效转换。

解决方案

关于NewSubrsIndexNonCID

这是XDocReport底层依赖的iText库中,处理非CID(字符识别)字体子集化时的核心数组变量,用于存储字体子表的索引信息。当字体文件损坏、不完整,或iText无法正确解析字体的子集元数据时,该变量会被置为null,触发空指针异常。

修复步骤

  1. 替换文档中的问题字体
    打开源ODT文档,将所有特殊字体、非系统兼容字体替换为Calibri、Arial等iText能稳定解析的通用字体。确保文档未使用损坏、未嵌入或罕见的字体类型。

  2. 修正字体注册逻辑
    原代码仅注册到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());
    
  3. 升级依赖版本
    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>
    
  4. 确保文档嵌入字体
    在LibreOffice/OpenOffice中打开ODT文档,通过文件 -> 属性 -> 字体检查所有使用的字体是否已嵌入到文档中,避免转换时依赖系统缺失的字体。


内容的提问来源于stack exchange,提问作者JavaDevS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 01:54:59