Why Developers Are Migrating to Apache PDFBox 3: Key Changes and Practical Examples

This article analyzes Apache PDFBox 3's major improvements over 2.x, including the new Loader API, incremental parsing for memory efficiency, rewritten IO layer with java.nio, and cleaner APIs, while providing practical code examples for loading PDFs, extracting text, and generating documents.

java1234
java1234
java1234
Why Developers Are Migrating to Apache PDFBox 3: Key Changes and Practical Examples

Introduction to PDFBox

Apache PDFBox is an open-source Java library under the Apache Foundation for creating, reading, writing, and converting PDFs. It is not just a preview tool but can be embedded in business systems for contract archiving, invoice generation, scanned document text extraction, and batch stamping.

Core capabilities include:

Reading existing PDFs to extract text, images, and form fields

Creating pages from scratch with text, lines, and images

Splitting, merging, encrypting, and digital signing

Rendering pages to PNG/JPEG for preview

Version 2.x was stable but accumulated baggage in memory usage, IO methods, and deprecated APIs. Version 3.0 addresses these underlying issues comprehensively.

What's New in PDFBox 3

Three key changes define PDFBox 3: unified loading via Loader, incremental parsing to save memory, and a rewritten IO layer.

1. Loading API Changed

Previously developers used PDDocument.load(...). In 3.0, loading methods are removed from PDDocument and unified under org.apache.pdfbox.Loader. This clarifies "from where to read and how to cache": files, byte arrays, and RandomAccessRead each have dedicated paths, no longer hidden in a single overloaded load method.

2. Incremental Parsing by Default

3.0 defaults to incremental parsing. If you only access page 1, it parses only objects relevant to page 1. For large files, reading only a few pages or stamping a single page keeps memory usage low. However, traversing all pages or scanning all annotations will still consume memory — inherent to the PDF format.

3. IO Layer Separated into pdfbox-io Module

Base IO classes moved to pdfbox-io, switching to java.nio at the bottom. File reading supports memory mapping and no longer relies on temporary scratch files. Write caching strategy replaces the old MemoryUsageSetting with the more flexible StreamCacheCreateFunction. Saving now enables compression by default, reducing ordinary document size; for PDF/A-1b scenarios with compression restrictions, it can be explicitly disabled.

The flow from opening to saving is cleaner than 2.x, a core reason many upgrade.

Why Teams Are Migrating

Upgrading has costs. Teams switch because these changes hit daily pain points:

Large files less intimidating: Customer service and archive systems with tens of MB, hundreds of pages scanned PDFs — 2.x loading often filled the heap. 3.0's incremental parsing and memory mapping make "read only a few pages" or "extract a text segment" practical.

Cleaner API: 2.x accumulated many @Deprecated methods. 3.0 removes outdated interfaces; fonts now use explicit Standard14Fonts.FontName. Migration requires fixing compile errors, but afterward code avoids "can this method still be used?" traps.

More transparent behavior: Previously InputStream loading silently copied to memory or temp files, making memory issues hard to debug. 3.0 removes InputStream overloads: you wrap in RandomAccessReadBuffer for memory, or use file/memory mapping for disk. More verbose, but control returns to you.

Ecosystem caught up: Spring projects, PDF toolchains, tutorials, and examples now target 3.x. New hires' first search results often show Loader.loadPDF. Staying on 2.x means maintenance cost eventually exceeds upgrade cost.

Real-World Scenarios with PDFBox 3

Adding Dependencies

<dependency>
    <groupId>org.apache.pdfbox</groupId>
    <artifactId>pdfbox</artifactId>
    <version>3.0.4</version>
</dependency>

For rendering pages to images, add pdfbox-tools. Use whatever 3.0.x version your project requires.

Opening PDFs with Loader

This is the line most changed when migrating from 2.x. Pass the file directly to Loader, auto-close with try-with-resources:

import java.io.File;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;

public class OpenPdfExample {
    public static void main(String[] args) throws Exception {
        File file = new File("report.pdf");
        try (PDDocument document = Loader.loadPDF(file)) {
            System.out.println("页数:" + document.getNumberOfPages());
            for (PDPage page : document.getPages()) {
                System.out.println("页面尺寸:" + page.getMediaBox());
            }
        }
    }
}

Password-protected files: Loader.loadPDF(file, "123456"). For very large PDFs where you want memory mapping and less heap usage:

import org.apache.pdfbox.io.RandomAccessReadMemoryMappedFile;

try (PDDocument document = Loader.loadPDF(
        new RandomAccessReadMemoryMappedFile(file))) {
    // Access pages on demand
}

Extracting Text

Common for archival retrieval and simple reconciliation:

import java.io.File;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;

public class ExtractTextExample {
    public static void main(String[] args) throws Exception {
        try (PDDocument document = Loader.loadPDF(new File("contract.pdf"))) {
            PDFTextStripper stripper = new PDFTextStripper();
            stripper.setStartPage(1);
            stripper.setEndPage(2);
            String text = stripper.getText(document);
            System.out.println(text);
        }
    }
}

Setting only the first two pages makes incremental parsing benefits obvious: no need to parse the entire contract for a two-page summary.

Generating a PDF from Scratch

In 3.0, standard fonts cannot use PDType1Font.HELVETICA; must use Standard14Fonts. This is where most compile errors appear during upgrade:

import java.io.IOException;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.font.Standard14Fonts;

public class CreatePdfExample {
    public static void main(String[] args) throws IOException {
        try (PDDocument document = new PDDocument()) {
            PDPage page = new PDPage(PDRectangle.A4);
            document.addPage(page);

            try (PDPageContentStream cs = new PDPageContentStream(document, page)) {
                cs.beginText();
                cs.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD), 20);
                cs.newLineAtOffset(72, 750);
                cs.showText("Invoice #2026-09-21");
                cs.endText();
            }

            // 3.0 defaults to compressed save, smaller file size
            document.save("invoice.pdf");
        }
    }
}

For Chinese content, standard 14 fonts are insufficient; embed TTF, e.g., PDType0Font.load(document, new File("msyh.ttf")). This approach is the same in 2.x and 3.x.

To merge PDFs, loop Loader.loadPDF and importPage into a new document. For page preview, use PDFRenderer 's renderImageWithDPI. These four tasks — extract, create, merge, render — cover most business needs.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Javamemory managementbackend developmentLoader APIPDFBoxPDF processingincremental parsingApache PDFBox 3
java1234
Written by

java1234

Former senior programmer at a Fortune Global 500 company, dedicated to sharing Java expertise. Visit Feng's site: Java Knowledge Sharing, www.java1234.com

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.