The two Java routes: Thymeleaf with Open HTML to PDF, or HttpClient
To generate a PDF from a template in Java without leaving the JVM, render an HTML template with Thymeleaf and convert it with Open HTML to PDF, a pure-Java library that outputs PDF through Apache PDFBox. The alternative is a template API called with the JDK's own java.net.http.HttpClient, available since Java 11.
The Java route has a constraint the Python and Node.js routes do not. Open HTML to PDF is not a browser. Its README says it does not run JavaScript and does not support flexbox or grid layout, so templates must use older CSS such as tables and floats. That is acceptable for invoices and statements and a poor fit for chart-heavy reports.
Route 1: Thymeleaf and Open HTML to PDF, step by step
Prerequisites. Maven or Gradle. The integration guide lists the artifacts openhtmltopdf-core and openhtmltopdf-pdfbox under the group com.openhtmltopdf, version 1.0.10. A community continuation of the project is published on Maven Central under io.github.openhtmltopdf. The library is LGPL licensed. Add Thymeleaf and Jsoup as well.
- Create the engine:
TemplateEngine templateEngine = new TemplateEngine();thentemplateEngine.setTemplateResolver(templateResolver); - Put data in a Thymeleaf context:
ctx.setVariable("invoiceNumber", "INV38379"); - Render to a string by passing a
StringWriter:templateEngine.process("invoice", ctx, writer); - Parse the HTML5 output and convert it to a W3C document:
org.w3c.dom.Document doc = new W3CDom().fromJsoup(Jsoup.parse(html)); - Configure the renderer:
PdfRendererBuilder builder = new PdfRendererBuilder();thenbuilder.useFastMode(); - Hand over the document and an output stream:
builder.withW3cDocument(doc, baseUri);thenbuilder.toStream(os); - Render:
builder.run();
In the template, Thymeleaf placeholders are attributes, for example <span th:text="${invoiceNumber}">INV0001</span>. The baseUri argument is what relative image and stylesheet paths resolve against. The builder also offers withUri(...) for a file or URL and withHtmlContent(html, baseDocumentUri) for a string that is already well-formed XHTML.
Route 2: a template API with java.net.http.HttpClient
Prerequisites. Java 11 or later, a CraftMyPDF account, a template ID and an API key. The Free plan allows 50 PDFs a month and 3 templates (pricing page, 3 October 2026). No extra dependency is needed.
- Create the client:
HttpClient client = HttpClient.newHttpClient(); - Build the request:
HttpRequest request = HttpRequest.newBuilder().uri(URI.create("https://api.craftmypdf.com/v1/create")).header("Content-Type", "application/json").header("X-API-KEY", apiKey).POST(BodyPublishers.ofString(json)).build(); - Send it:
HttpResponse<String> response = client.send(request, BodyHandlers.ofString()); - Check
response.statusCode()and parseresponse.body()with your JSON library. Thefilefield holds the PDF link.
The JSON body needs template_id and data; export_type chooses between a link (json) and the raw file (file). For the raw file, use a binary handler such as BodyHandlers.ofInputStream(). The CraftMyPDF API guide lists the remaining parameters.
Worked example: a statement with a repeating table
A customer statement has a header, a table of transactions and a total. In Thymeleaf the table rows repeat over a list set with ctx.setVariable(...), and the layout uses an HTML table, the kind of older layout the Open HTML to PDF README points to. Rendering runs in-process, so there is no browser to install on the application server and no per-document fee.
The same statement through the API is a JSON object with a transactions array inside data. The template is designed in the editor against the same JSON structure.
| Thymeleaf + Open HTML to PDF | Template API (CraftMyPDF) | |
|---|---|---|
| JavaScript, flexbox, grid | Not supported | Not relevant; layout is built in the editor |
| Runs on | Your JVM | The vendor's servers |
| Cost | Open source (LGPL) | Free for 50 PDFs a month, then from $29 a month |
| Layout edited by | A developer | Anyone with editor access |
A mistake to avoid: giving a non-browser engine browser HTML
The mistake to avoid is treating Open HTML to PDF like Chrome. Its README says the native XML parser cannot interpret the full HTML specification, which is why the project recommends parsing with Jsoup first, as in step 4. Flexbox, grid and JavaScript are outside what the README says the library supports, so a page that depends on them needs reworking, and colors with transparency are not supported.
If your template needs real browser rendering and you want to stay in Java, Playwright for Java documents page.pdf(new Page.PdfOptions().setPath(Paths.get("page.pdf"))) after page.setContent(html). That brings a browser download with it. If you would prefer to run nothing, use route 2.
For drawing documents element by element, Apache PDFBox is the low-level Java PDF library underneath. Whichever you pick, pin template versions (how template versioning works), test multi-page tables against the page breaks guide, and read the three template routes if you are still deciding.
Sources used for this page
The facts above come from the pages below, read on 3 October 2026. We have not used these products hands-on. Prices and terms change, so confirm them on the vendor's site before you buy.
- Open HTML to PDF wiki: Integration Guide — Vendor documentation · github.com · checked 2026-10-03
- Open HTML to PDF README (community repository) — Vendor documentation · github.com · checked 2026-10-03
- Open HTML to PDF source: BaseRendererBuilder.java — Vendor documentation · github.com · checked 2026-10-03
- Tutorial: Using Thymeleaf (3.1) — Vendor documentation · thymeleaf.org · checked 2026-10-03
- HttpClient (Java SE 21 API) — Vendor documentation · docs.oracle.com · checked 2026-10-03
- HttpRequest.BodyPublishers (Java SE 21 API) — Vendor documentation · docs.oracle.com · checked 2026-10-03
- Page | Playwright Java — Vendor documentation · playwright.dev · checked 2026-10-03
- Apache PDFBox: a Java PDF library — Vendor documentation · pdfbox.apache.org · checked 2026-10-03
- CraftMyPDF API Reference (OpenAPI specification) — Vendor documentation · craftmypdf.com · checked 2026-10-03
- Pricing - CraftMyPDF.com — Vendor pricing page · craftmypdf.com · checked 2026-10-03
- HttpResponse.BodyHandlers (Java SE 21 API) — Vendor documentation · docs.oracle.com · checked 2026-10-03