Skip to content

Jafly. Utils

Utils

Render FreeMarker templates and convert rendered content to document formats; mark filter DTO fields.

Use TemplateRenderUtil for template rendering and document output, and UserFilterDTO for the filter metadata consumed by the R2DBC utilities. Keep template resources and model data under application control.

Maven artifact Packaging Source project
org.fireflyframework:fireflyframework-utils jar modules/utils

Part of Team-wide architecture.

In the onboarding service

After accepting an application, the service can render a confirmation template or generate a PDF receipt. Template data and document storage remain application choices.

Add the component

Installation and version availability explains source builds and published releases.

<dependency>
    <groupId>org.fireflyframework</groupId>
    <artifactId>fireflyframework-utils</artifactId>
    <version>26.10.20-SNAPSHOT</version>
</dependency>

Quick start

The Java examples in this section are API fragments for application code. Use the stated imports and supply the application-owned collaborators described alongside them.

Render a template to HTML

Place invoice.ftl under src/main/resources/templates/:

<!-- src/main/resources/templates/invoice.ftl -->
<html><body>
  <h1>Invoice for ${customerName}</h1>
  <p>Total: ${total}</p>
</body></html>
import org.fireflyframework.utils.template.TemplateRenderUtil;
import java.util.Map;

Map<String, Object> model = Map.of("customerName", "Acme Corp", "total", "1,250.00 EUR");

String html = TemplateRenderUtil.renderTemplateToHtml("invoice.ftl", model);

Render a template straight to PDF bytes

byte[] pdf = TemplateRenderUtil.renderTemplateToPdfBytes("invoice.ftl", model);
// e.g. return as a ResponseEntity<byte[]> with Content-Type: application/pdf

Customize the PDF (watermark, encryption, metadata, bookmarks)

import org.fireflyframework.utils.template.TemplateRenderUtil.PdfOptions;
import org.fireflyframework.utils.template.TemplateRenderUtil.PdfOptions.PageSize;

PdfOptions options = new PdfOptions()
        .withPageSize(PageSize.A4)
        .withMargins(36, 36, 36, 36)
        .withDefaultFont("DejaVu Sans")
        .withFontDirectory("/opt/fonts")              // embeds .ttf/.otf found here
        .withWatermark("CONFIDENTIAL", 0.3f, 60, 45, "#888888")
        .withMetadata("Q1 Invoice", "Billing", "Invoice", "invoice,billing")
        .withEncryption("ownerSecret")                // owner password, printing/copy allowed
        .withBookmark("Summary", "1")
        .withChildBookmark("Line Items", "1");

byte[] pdf = TemplateRenderUtil.renderTemplateToPdfBytes("invoice.ftl", model, options);

Render asynchronously

import java.util.concurrent.CompletableFuture;

CompletableFuture<byte[]> future =
        TemplateRenderUtil.renderTemplateToPdfBytesAsync("invoice.ftl", model);

Render an HTML fragment to an image

byte[] png = TemplateRenderUtil.renderHtmlToImage(
        "<h1 style='color:#0a6'>Hello</h1>", 800, 400, "png");

Mark a filterable ID on a filter DTO

import org.fireflyframework.utils.annotations.FilterableId;
import java.util.UUID;

public class UserFilterDTO {
    @FilterableId
    private UUID customerId;   // included in filters with exact matching, exposed as a query param

    private UUID accountId;    // excluded from filters (default behaviour for *Id fields)

    private String name;       // regular field with full filtering capabilities
}

Configuration and wiring

This module declares no @ConfigurationProperties class of its own. Use the constructor/port contracts above and the configuration of the host or related core module.

Public API and extension points

Type Contract and responsibility
TemplateRenderUtil Utility for rendering FreeMarker templates to XHTML, PDF, and images using Flying Saucer.
FilterableId The FilterableId annotation is used to mark ID fields that should be included in filtering operations.
Related component Why it belongs nearby
Kernel Share a consistent exception vocabulary across application, domain, and infrastructure boundaries.

Build and test

Use Java 25. From the repository root, build this component with its required dependencies:

git clone https://github.com/fireflyframework/fireflyframework-jafly.git
cd fireflyframework-jafly
./mvnw -pl :fireflyframework-utils -am verify
./mvnw -pl :fireflyframework-utils -am install

verify runs the selected projects' tests. install makes the current build available in your local Maven repository.

Representative test sources:

Test fixture

The testRenderHtmlToImage test demonstrates one concrete behavior. Excerpt from TemplateRenderUtilTest.java. The test class supplies its fixtures and imports.

@Test
void testRenderHtmlToImage() throws Exception {
    // Create a simple HTML content
    String html = "<html><body><h1 style='color:blue'>Image Test</h1></body></html>";

    // Render to image
    byte[] imageBytes = TemplateRenderUtil.renderHtmlToImage(html, 400, 200, "png");

    // Verify image was created
    assertNotNull(imageBytes);
    assertTrue(imageBytes.length > 0, "Image should not be empty");

    // Verify it's a PNG image by checking the header
    byte[] pngHeader = {(byte)0x89, 'P', 'N', 'G'};
    byte[] actualHeader = new byte[4];
    System.arraycopy(imageBytes, 0, actualHeader, 0, 4);
    assertArrayEquals(pngHeader, actualHeader, "Image should be a PNG");
}

Detailed reference

Configuration

This module has no Spring @ConfigurationProperties and no auto-configuration. There are no firefly.* properties to set in application.yml. TemplateRenderUtil is configured programmatically via its static methods, which apply globally to the utility:

Method Purpose Default
setTemplateCachingEnabled(boolean) Enable/disable in-memory template caching enabled
setTemplateCacheMaxSize(int) Max number of cached compiled templates 100
setAsyncThreadPoolSize(int) Size of the async rendering thread pool max(2, availableProcessors())
addSharedVariable(name, value) Expose a variable to every template none
setTemplatePreProcessor(BiFunction) Transform template source before rendering none
setTemplatePostProcessor(BiFunction) Transform rendered output after rendering none
addTemplateLoader(TemplateLoader) Register an additional FreeMarker loader classpath + ./templates
setTemplateDirectory(String) / setClasspathAndFileTemplateLoaders(...) Override where templates are loaded from classpath:/templates, then ./templates

Template lookup order with its default configuration: classpath:/templates, then the working-directory ./templates folder, then any custom loaders. FreeMarker defaults: UTF-8 encoding, Locale.US, and a rethrow exception handler.

Call TemplateRenderUtil.shutdownAsyncThreadPool() on application shutdown if you used the async APIs.

Continue the application

Use the Notifications Core guide for the next part of this integration. The runnable submission/query service is in Getting started.

Source and further reading