Free tools Windows power users keep installed
One-click scans. No signup required.
Use Apache PDFBox to create the PDF, save it in storage you control, and expose it through an HTTP route such as GET /documents/{id}.pdf. The route—not the file’s server path—is the URL your client retrieves. On retrieval, authorize the request and stream the bytes with Content-Type: application/pdf; choose an inline or attachment disposition depending on whether the browser should display or download the file.
How the create-and-retrieve flow works
Generating a PDF and making it available by URL are separate jobs. PDFBox creates document bytes; your application decides where those bytes live, who can access them, how long they remain available, and which URL maps to them.
- Validate the data used to create the document and generate an opaque identifier. Do not use a user-provided filename as a filesystem path.
- Create the PDF with PDFBox and save it to a controlled destination, such as a private directory, database/blob store, or object storage.
- Return a URL or relative resource path associated with the identifier.
- On a later GET request, authorize the caller, find the document, and stream it with PDF response headers.
Keep the public route separate from the storage layout. A URL should identify an application resource, not reveal a machine-specific path such as /srv/app/uploads/report.pdf. Decide whether the URL is session-protected, permanent, or signed and expiring; a hard-to-guess identifier alone is not authorization.
Choose a Java PDF library and version
Apache PDFBox is an open-source Java library for creating and working with PDF documents. Its documented PDDocument API can save to a filename, file, or OutputStream, so it supports both persisted-file and streaming designs. The project lists PDFBox 3.0.8, released July 11, 2026, and 2.0.37, released July 15, 2026. Pin the version you use and consult the official PDFBox project and API documentation when upgrading.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →The PDFBox repository mirror documents Java 11 or higher and Maven 3 as build prerequisites. Check the current project guidance for your environment before choosing a runtime or upgrading a major version.
Create and save a PDF with PDFBox
This small Java example creates a one-page PDF and saves it to a controlled output directory. It uses PDFBox 3.0.8 and Java 11 or later. PDFBox’s standard Helvetica font is suitable for this simple ASCII example; use an embedded TrueType font for broader Unicode coverage.
Rank #2
Add the dependency to Maven:
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>3.0.8</version>
</dependency>
Then create the document:
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.font.Standard14Fonts;
public final class MakePdf {
public static void main(String[] args) throws IOException {
Path directory = Path.of("generated").toAbsolutePath().normalize();
Files.createDirectories(directory);
Path output = directory.resolve("welcome.pdf");
try (PDDocument document = new PDDocument()) {
PDPage page = new PDPage();
document.addPage(page);
try (PDPageContentStream content = new PDPageContentStream(document, page)) {
content.beginText();
content.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA), 18);
content.newLineAtOffset(72, 720);
content.showText("Generated with Apache PDFBox");
content.endText();
}
document.save(output.toFile());
}
System.out.println("Saved PDF to: " + output);
}
}
The example uses a fixed filename only to keep the demonstration short. In a web application, derive a storage key from an application-generated identifier and ensure the resolved file remains inside the configured storage root. Never concatenate a request parameter directly into a path.
Expose the file through an HTTP URL
A typical creation endpoint returns a resource reference, for example {"id":"opaque-id","url":"/documents/opaque-id.pdf"}. The retrieval endpoint resolves that ID through authorized application logic. Set Content-Type: application/pdf. Use Content-Disposition: inline; filename="report.pdf" if the browser should try to display it, or attachment when downloading is the intended behavior. Sanitize the filename used in the header.
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →In Spring, the controller can return a ResponseEntity<Resource> backed by a file or storage stream, with the headers above. Spring’s reference documentation covers PDF views generated from model data and identifies OpenPDF as a preferred library for that view support; that does not establish that OpenPDF is best for every application. Keep document generation in a service and retrieval authorization in the request path rather than treating a static file URL as automatically safe.
- Add
Content-Lengthif the storage layer knows the size. If it does not, let the web stack stream the response using its supported transfer mechanism. - Return a deliberate not-found response for an unknown ID. If an object has expired or been deleted, define whether clients receive a not-found or gone response.
- Close
PDDocument, content streams, and opened input/output streams with try-with-resources or the equivalent lifecycle mechanism. - For large documents, stream from storage instead of reading the entire file into an additional heap byte array.
Return generated bytes directly instead of saving first
If the caller needs the PDF immediately and you do not need a reusable URL, PDFBox can save to an OutputStream. In a Spring endpoint, that stream can be the response body; set the PDF content type and disposition before writing. This avoids a permanent file, but it does not provide a later URL by itself. To offer both an immediate response and later retrieval, persist the document or upload it to object storage, then return the resource URL.
Rank #4
For a small document, buffering in memory may be convenient. For large output or high concurrency, account for the memory cost of buffering and prefer streaming or storage-backed responses. The appropriate choice depends on the document size, request volume, and storage lifecycle; no throughput figure is implied here.
Fonts, layout, and document lifecycle
PDF generation is not just writing text at coordinates. Decide page size, margins, font embedding, character coverage, line wrapping, and page breaks based on the content. PDFBox’s command-line documentation highlights formatting dimensions such as charset, font size, line spacing, margins, page size, standard fonts, TrueType fonts, and output path; the same concerns apply when you build the document through its Java API.
Best Value
- Unicode: Standard PDF fonts do not cover every script or symbol. Embed a suitable TrueType font when the content requires wider character support, and verify that its license permits embedding.
- Long content: Implement wrapping and page-break logic, or use a higher-level layout approach. Do not assume a text operation automatically flows content onto another page.
- Images and resources: Validate source inputs and close streams after use. Large images can increase output size and memory use.
- Cleanup: Close each document and content stream even when generation throws an exception, so file handles and other resources are not left open.
Storage, security, and URL lifetime
Choose storage according to the document’s lifetime and access pattern. A local directory may suit a single-instance service with a managed disk; a database/blob store or object storage may fit a distributed deployment. In all cases, keep storage private unless public access is an intentional requirement.
- Generate opaque IDs on the server and map them to stored objects.
- Check authorization on every retrieval request; do not rely on obscurity of the URL.
- Define retention and deletion behavior. Expiring documents should stop resolving after expiration.
- Use signed, expiring links only when their bearer-token behavior matches your security model.
- Apply access controls and limits to document creation so attackers cannot use the endpoint to exhaust CPU, disk, or storage quota.
Troubleshooting common failures
- The file is empty or unreadable: Ensure content streams are closed before saving and that content operations are complete. Confirm that the save operation succeeds and that the HTTP response is returning the stored bytes rather than an error page.
- Characters are missing or replaced: The selected font may not contain the glyphs. Embed a font that supports the required script, and verify the document with representative text.
- The URL returns 404: Check that the creation response uses the same identifier format as the retrieval route, that storage succeeded, and that any cleanup or expiration policy has not removed the file.
- The browser downloads instead of displaying: Check the
Content-Dispositionvalue and filename. Useinlinefor display intent; browser behavior can still depend on browser settings. - The URL exposes or accesses the wrong file: Do not map untrusted path fragments to filesystem locations. Resolve an opaque ID through controlled storage metadata and enforce authorization.
- Large responses consume too much memory: Avoid copying the entire PDF into a byte array when storage can provide a stream. Check that the HTTP framework and any proxy are not buffering the whole response.
- Dependency or runtime errors appear after an upgrade: Confirm the Java and Maven prerequisites and the pinned PDFBox version, then follow the project’s migration notes for major-version changes.
Or skip the browser setup
If your actual need is to capture a webpage as a PDF rather than generate a custom PDF from Java data, ScreenshotNeo is a separate website screenshot API and MCP server. It can return a PDF, but it does not replace PDFBox for drawing a document from application data. The one-call example below is the documented request shape; consult the ScreenshotNeo API documentation for PDF output options.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before capture. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots, and the free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000. Sign up free for 1,000 screenshots a month, with no card required.
Frequently Asked Questions
Does generating a PDF automatically give me a public URL?
No. A URL exists only after your application exposes the generated document through a route or storage service.
Can I use ScreenshotNeo to generate a custom Java PDF?
No. It captures webpages as PDFs; PDFBox is the relevant choice for generating a document from Java application data.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




