Skip to content

Binary rendering for max throughput

Version note

Available since jte 1.7.0.

Most template parts are static content, and only a few parts of a template are dynamic. Encoding those static parts repeatedly on every request is wasteful if your web framework sends binary UTF-8 content to the user. jte makes it possible to encode those static parts when the template is compiled:

templateEngine.setBinaryStaticContent(true);
templateEngine.binaryStaticContent = true

Apply binary encoding when compiling your application by using precompiled templates.

This generates a binary content resource for each template. Those pre-encoded UTF-8 byte[] arrays are loaded in memory from the resource file together with the template class. This also implies that the constant pool is released from holding template strings.

To fully benefit from binary templates, you must use a binary template output, like gg.jte.Utf8ByteOutput. This output is heavily optimized to consume as little CPU and memory as possible when using binary templates.

Info

You will only see a performance increase if you use binaryStaticContent with a binary output. Other outputs convert the pre-encoded byte[] arrays back to Java Strings, defeating this optimization.

Example usage with HttpServletResponse:

Utf8ByteOutput output = new Utf8ByteOutput();
templateEngine.render(template, page, output);

response.setContentLength(output.getContentLength());
response.setContentType("text/html");
response.setCharacterEncoding("UTF-8");
response.setStatus(page.getStatusCode());

try (OutputStream os = response.getOutputStream()) {
    output.writeTo(os);
}
val output = Utf8ByteOutput()
templateEngine.render(template, page, output)

response.contentLength = output.contentLength
response.contentType = "text/html"
response.characterEncoding = "UTF-8"
response.status = page.statusCode

response.outputStream.use { os ->
    output.writeTo(os)
}

There are a few pretty cool things going on here:

  • We know about the binary Content-Length directly after rendering, at no additional cost
  • All static parts are streamed directly to the output stream without any copying/encoding overhead
  • Dynamic parts are usually small - and written very efficiently to internal chunks during rendering

With binary content, you can render millions of pages per second (in case there's no DB or other external service interaction) with minimal CPU, memory and GC usage.