使用更少的内容很容易在 iText 7.0.x 中重现此行为:
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
Document doc = new Document(pdfDoc);
doc.add(new AreaBreak(AreaBreakType.NEXT_PAGE));
doc.add(new AreaBreak(AreaBreakType.NEXT_PAGE));
PdfTextFormField field = PdfFormField.createText(pdfDoc, new Rectangle(100, 100, 300, 20), "name", "");
PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, true);
form.addField(field);
doc.close();
这背后的问题是,对于没有关联页面的表单字段(小部件),iText 尝试通过迭代所有文档页面并查找它们各自的注释数组来确定小部件所在的页面。并且它已经这样做了createText
,同时设置字段值(并更新小部件外观)...
不过,在上面的代码中,之前新创建的页面(至少是第一个页面)已经被刷新到写入器并在内存中取消初始化。因此,页面上的循环尝试从未初始化的页面字典中检索值,即从null Map
,因此NullPointerException
.
我不知道这是 iText 中的错误还是仅仅是反模式。
受到@SamuelHuylebroeck评论的启发,我尝试了OP的原始代码和上面的简化代码immediateFlush
set to false
。事实上,这可以防止异常,并且简化代码的结果看起来不错。然而,OP原始代码的结果并不像他预期的那样,该表是跨四页构建的,但所有字段都出现在最后一页上!
因此,如果表单元素是直接创建的(即不通过事件)设置immediateFlush
to false
可以被认为是解决方法 (but 不是修复因为早期刷新是 iText 的一个重要特性)。不过,表单创建的一般情况已被破坏,除非有人可以指出这里的代码是 iText 7 反模式并且可以展示应该如何完成。