Stack · Java
Generate PDFs in Java
Java's usual options both bite. Flying Saucer renders XHTML with roughly CSS 2.1 support, so modern layout silently falls apart. iText is capable but AGPL — using it in a closed-source product means buying a commercial licence.
If Thymeleaf already renders the document for the browser, render it to a string and POST it. java.net.http.HttpClient has been in the JDK since 11, so this adds no dependency at all.
01Call it from Java
// PdfService.java
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.Map;
@Service
public class PdfService {
private final HttpClient client = HttpClient.newHttpClient();
private final ObjectMapper mapper = new ObjectMapper();
public byte[] render(String html) throws Exception {
String body = mapper.writeValueAsString(Map.of(
"html", html,
"options", Map.of("format", "A4", "pageNumbers", true)
));
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://rendral.com/api/v1/pdf"))
.header("Authorization", "Bearer " + System.getenv("RENDRAL_API_KEY"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<byte[]> response =
client.send(request, HttpResponse.BodyHandlers.ofByteArray());
if (response.statusCode() >= 300) {
throw new IllegalStateException("Render failed: " + response.statusCode());
}
return response.body();
}
}Frequently asked
How do I render a Thymeleaf template to a string?
Call templateEngine.process("invoice", context) with a Context holding your model. That returns the same HTML the browser would receive.
Does this avoid the iText licence question?
Yes. iText is AGPL, which generally requires a commercial licence for closed-source products. This is an API call with no source-licensing implications.
What's wrong with Flying Saucer?
Nothing, within its scope — but it targets XHTML with roughly CSS 2.1. Flexbox, grid and modern web fonts aren't supported, so contemporary templates break.
Do I need an HTTP library?
No. java.net.http.HttpClient ships with the JDK from 11 onward, so there's no new dependency to justify in review.
Related
Packing slips PDF API
Generate packing slips and pick lists as PDFs from HTML.
Compare vs PDFCrowd
How PDFCrowd and Rendral differ on pricing, features, and setup.
PDFs in Next.js
A step-by-step guide to generating PDFs from Next.js.
A free tier, five endpoints, and SDKs for Node and Python.