Hi all,
I'm using PDFBox in a GraalVM native-image CLI that only does non-rendering
work: reading metadata and embedding an attachment. It never renders pages
or touches images. I'd appreciate your advice on a small robustness
question rather than reporting it as an outright bug.
org.apache.pdfbox.pdmodel.PDDocument has a static initializer that eagerly
warms up the RGB color subsystem:
/* avoid concurrency issues with PDDeviceRGB */
static {
try {
WritableRaster raster = Raster.createBandedRaster(
DataBuffer.TYPE_BYTE, 1, 1, 3, new Point(0, 0));
PDDeviceRGB.INSTANCE.toRGBImage(raster);
} catch (IOException ex) {
LOG.debug("voodoo error", ex);
}
}
I understand the intent: avoiding a first-use concurrency race in color
management. The eager warm-up itself seems reasonable.
The problem is the failure mode. The block only catches IOException. If AWT
native libraries cannot be loaded, the warm-up throws UnsatisfiedLinkError
instead. That is an Error, so it is not caught. As a result, PDDocument
class initialization fails with ExceptionInInitializerError, and PDDocument
becomes unusable even for operations that do not need rendering or color
conversion.
Minimal reproducer:
//DEPS org.apache.pdfbox:pdfbox:3.0.7
import java.io.File;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
public class PdfBoxMwe {
public static void main(String[] args) throws Exception {
try (PDDocument doc = Loader.loadPDF(new File(args[0]))) {
System.out.println("pages: " + doc.getNumberOfPages());
}
}
}
This works on a normal JVM. It fails when built as a GraalVM native image
where the AWT native libraries are unavailable or not loadable.
Stack excerpt, using PDFBox 3.0.7, JDK 25, GraalVM/Liberica NIK native
image, macOS arm64:
java.lang.UnsatisfiedLinkError: Can't load library:
.../libawt_lwawt.dylib
at java.awt.image.ColorModel.loadLibraries(ColorModel.java:208)
at java.awt.image.ColorModel.<clinit>(ColorModel.java:215)
at java.awt.image.Raster.<clinit>(Raster.java:172)
at
org.apache.pdfbox.pdmodel.PDDocument.<clinit>(PDDocument.java:103)
at org.apache.pdfbox.Loader.loadPDF(Loader.java:...)
...
Note: this is not strictly macOS-specific. A similar failure also occurs on
Linux with GraalVM CE, where the AWT native libraries are not bundled. The
symptom is different there (NoClassDefFoundError:
java.awt.GraphicsEnvironment), but it comes from the same
PDDocument.<clinit> path. It works on Linux only when the toolchain bundles
AWT (e.g. Liberica NIK).
The specific PDF does not matter. The failure happens in PDDocument's
static initializer, before any document content is parsed. Even new
PDDocument() can trigger it.
My question: would it be reasonable to broaden the catch in that static
block, for example by catching LinkageError or Throwable, logging it, and
continuing? The warm-up would still run where available. Environments
without AWT would skip it, leaving PDDocument usable for non-rendering
operations such as parsing, metadata, and attachments. Rendering or color
conversion could still fail later when actually used.
I searched first: PDFBOX-4746
<https://issues.apache.org/jira/browse/PDFBOX-4746> looks related but is a
different build-time native-image issue. There is also related GraalVM
context <https://github.com/oracle/graal/issues/13272> about macOS AWT
support in native-image (oracle/graal#13272).
Happy to open a JIRA enhancement and/or submit a PR if this direction
sounds acceptable.
Thanks for the great library.
Best regards,
Wanling