Clients

Java client

Install the Java client, render a PDF from Java code in a child process or through brevier serve, and handle errors. Runs on Java 8 and newer.

On this page

Community

The Java client calls the Brevier engine from your Java code. You pass HTML and data, and you get the PDF back. The client runs on Java 8 and newer. The engine does the layout, so you write no PDF drawing code.

There are two modes:

Mode How the client reaches the engine Use it for
Child process It starts the brevier command for each render. Development, scripts and batch jobs
Serve mode It calls a running brevier serve over HTTP. Production and many renders

Install the engine

The engine is the brevier command. Child process mode starts it, so it must be on the PATH of the machine that runs your Java code:

pip install brevier

Other ways to install it are on the Installation page.

Get a trial key

Every render needs a licence key, also for testing. Get the key before the first render.

  1. Request a free 30-day trial key on the pricing page. It arrives by email.
  2. Set the BREVIER_LICENCE_KEY environment variable:
Linux and macOS
export BREVIER_LICENCE_KEY="<your-licence-key>"
Windows PowerShell
$env:BREVIER_LICENCE_KEY = "<your-licence-key>"

The engine reads the key from its environment. The Java client passes your environment on to the child process. In serve mode, set the key in the shell that starts brevier serve.

Add the client

Gradle
implementation 'dev.brevier:brevier:0.6.0'
Maven
<dependency>
  <groupId>dev.brevier</groupId>
  <artifactId>brevier</artifactId>
  <version>0.6.0</version>
</dependency>

Child process

This program renders a PDF from an HTML string and a map:

Hello.java
import dev.brevier.Pdf;
import java.nio.file.Paths;
import java.util.Collections;

public class Hello {
    public static void main(String[] args) {
        Pdf.builder()
            .withHtml("<h1>Hello {{ name }}</h1>")
            .withData(Collections.singletonMap("name", "World"))
            .toFile(Paths.get("hello.pdf"));
    }
}

Run it. The folder now has hello.pdf.

  • withHtml and withCss take the layout as text or as a Path.
  • withData takes any Java object: a Map or a bean. withJson takes JSON text.
  • toBytes returns the PDF. toFile writes it to a path.

Serve mode

In serve mode the engine runs as a service, and your code asks it for a PDF by the name of a template. A template is a folder with a file of the same name:

templates/hello/hello.html
<!DOCTYPE html>
<html lang="en">
<body>
  <h1>Hello {{ name }}</h1>
</body>
</html>

Start the server in the folder that holds templates:

brevier serve --templates templates

The server listens on 127.0.0.1:8080. It has no TLS and no login, so put a gateway in front of it before you expose it. Then render the template from Java:

HelloServe.java
import dev.brevier.Brevier;
import dev.brevier.transport.HttpTransport;
import java.nio.file.Files;
import java.nio.file.Paths;

public class HelloServe {
    public static void main(String[] args) throws Exception {
        byte[] pdf = Brevier.template("hello")
            .withTransport(new HttpTransport("http://127.0.0.1:8080"))
            .with("name", "World")
            .render();
        Files.write(Paths.get("hello.pdf"), pdf);
    }
}
  • with(name, value) sets one root of the template. with(map) sets several.
  • rows(list) sets the rows of a table.
  • render(objects...) binds each object to the root of its type.
  • Without withTransport, the client starts brevier serve --stdio as a child process. It reads the templates folder of the working directory and reuses the process.

How do I render many PDFs at once?

Pdf.batch() renders every HTML file of a folder, and its subfolders, into one PDF each. All files get the same CSS. The batch passes no data: each file must already be the finished page, for example from your own template engine.

Batch.java
import dev.brevier.Pdf;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;

public class Batch {
    public static void main(String[] args) {
        List<Path> written = Pdf.batch()
            .withInput(Paths.get("letters"), "*.html")
            .withCss(Paths.get("company.css"))
            .withOutput(Paths.get("out"))
            .toFiles();
        written.forEach(System.out::println);
    }
}

With letters/2026-001.html and letters/2026-002.html, the program prints one line per PDF it wrote, in the order it found the files:

Output
out/2026-001.pdf
out/2026-002.pdf

For one PDF per record of your data, call Pdf.builder() in a loop instead. A subfolder of letters comes back as the same subfolder of out. When one file fails, toFiles throws a BrevierException.

How do I send the PDF from a web endpoint?

Render to bytes and return them with the content type application/pdf. In Spring Boot:

InvoiceController.java
@GetMapping(value = "/invoices/{id}/pdf", produces = MediaType.APPLICATION_PDF_VALUE)
public byte[] invoice(@PathVariable String id) {
    return Brevier.template("rechnung").render(invoices.find(id));
}

invoices is your own data access. For many requests, run brevier serve and pass an HttpTransport, as in Serve mode.

How do I get HTML instead of a PDF?

Html.builder() takes the same calls as Pdf.builder() and returns HTML. Use it to show the document in a web portal, or to compare it in a test:

byte[] html = Html.builder()
    .withHtml("<h1>Hello {{ name }}</h1>")
    .withData(Collections.singletonMap("name", "World"))
    .toBytes();

The class names of this HTML stay stable between releases. Output and tests shows how to use it in a snapshot test.

Replace a JasperReports or Word call

If your service fills a JasperReports report or a Word file today, import the template first. Then replace the call in two steps.

Step 1 keeps your map of parameters and passes the rows:

return Brevier.template("kontoauszug").with(params).rows(buchungen).render();

Step 2 passes your objects. The client binds each object to the root of its type.

return Brevier.template("kontoauszug").render(konto, kunde, buchungen);

Errors

The client throws a BrevierException. It has getCode(), the error code of the engine such as DATA_ERROR, and getPath(), the place in the data where the problem is. The message never holds a value from your data.