Itext Java 11: com.itextpdf.io.source.ByteBufferRandomAccessSource$1存在非法反射访问

6

最近升级到Java 11并开始执行回归检查。尝试调用com.itextpdf.text.pdf.PdfReader.close时,目前会收到非法反射访问错误。目前使用的是Itext版本5.5.13,但也尝试了Itext 7.0.0并遇到了同样的问题。

有没有人对如何解决Java-11和Itext之间的兼容性问题有什么建议?

警告:发生了非法反射访问操作警告:非法反射访问者为 com.itextpdf.io.source.ByteBufferRandomAccessSource$1 (file:...repository/com/itextpdf/io/7.0.0/io-7.0.0.jar),被访问的方法为 java.nio.DirectByteBuffer.cleaner()警告:请考虑向 com.itextpdf.io.source.ByteBufferRandomAccessSource$1 的维护者报告此问题警告:使用 --illegal-access=warn 启用进一步非法反射访问操作的警告警告:所有非法访问操作都将在将来的版本中被拒绝


你尝试使用最新的iText版本(截至今天为止是7.1.4)了吗?我相信在Java 9上也遇到了类似的问题,并且我认为已经解决了。 - Yulian Gaponenko
如果您找到了解决方案,能否为iText 7提交一个pull request呢?那将是非常好的!但我们不会为iText 5更新,因为它已经到了生命周期的尽头。 - Amedee Van Gasse
还有,你能在7.1.4版本中重现吗? - Amedee Van Gasse
是的,我在7.1.4也遇到了同样的问题。 - D. Millard
2个回答

9
虽然我同意鼓励您调试代码并找到根本原因(然后提交拉取请求),或者如果您是带支持合同的客户,则在iText Jira中创建问题(这将提高问题的优先级)。但是,这里有一个解决方法建议(我没有测试过,但是很可能会起作用):
使用接受InputStream和OutputStream的PdfReader和PdfWriter构造函数。在这种情况下,不应该调用导致问题的代码。对于iText与文件系统交互的所有其他情况 - 将所有内容包装在InputStream/OutputStream中,或处理byte[]数组。
所以这一行:
new PdfDocument(new PdfReader(inFilePath), new PdfWriter(outFilePath))

成为这个:

new PdfDocument(new PdfReader(new FileInputStream(inFilePath)), 
                new PdfWriter(new FileOutputStream(outFilePath)))

你可能还想将流包装成BufferedInputStream/BufferedOutputStream
同样,在处理PdfFontFactory时,使用接受byte[]而不是表示文件路径的String的方法。

将PdfWriter和PdfReader字符串包装在新的FileOutputStreams FileInputStreams中确实解决了它。 - D. Millard
从PdfReader(String path)更改为PdfReader(InputStream is)解决了它。 - jhuamanchumo

1
如果您想了解什么是非法反射访问,请参考这里:什么是非法反射访问 这个特定的警告来自于这个类:

https://github.com/itext/itext7/blob/develop/io/src/main/java/com/itextpdf/io/source/ByteBufferRandomAccessSource.java

从这个特定的方法中:
private static boolean clean(final java.nio.ByteBuffer buffer) {
    if (buffer == null || !buffer.isDirect())
        return false;

    Boolean b = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
        public Boolean run() {
            Boolean success = Boolean.FALSE;
            try {
                // java 9
                if (UNMAP_SUPPORTED)
                    CLEANER.freeBuffer(buffer.toString(), buffer);
                // java 8 and lower
                else {
                    Method getCleanerMethod = buffer.getClass().getMethod("cleaner", (Class<?>[]) null);
                    getCleanerMethod.setAccessible(true);
                    Object cleaner = getCleanerMethod.invoke(buffer, (Object[]) null);
                    Method clean = cleaner.getClass().getMethod("clean", (Class<?>[]) null);
                    clean.invoke(cleaner, (Object[]) null);
                }
                success = Boolean.TRUE;
            } catch (Exception e) {
                // This really is a show stopper on windows
                Logger logger = LoggerFactory.getLogger(ByteBufferRandomAccessSource.class);
                logger.debug(e.getMessage());
            }
            return success;
        }
    });

    return b;
}

This line exactly:

getCleanerMethod.setAccessible(true);

只要这个警告不会影响iText的正常工作,我认为你最好的做法是向iText团队提交问题/PR,并等待适当的修复措施可用。

不幸的是,PdfDocument对象似乎没有关闭文档。在调试过程中也可以看到,由于itext仍然持有pdf文件,因此无法手动删除该文件。 - D. Millard
那么这就是一个重大的错误。您可能希望调试iText流本身以找出根本原因。简单的警告不应该破坏资源关闭等重要事项。 - Mikhail Kholodkov
代码不应该通过“// java 8及以下”分支,而是应该通过“// java 9”分支吗? - Holger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接