Clash of Java Templates: A Story of Sizing
Lucas Panier6 min read
In this article, I will compare different Java template engines. Indeed, during one of my projects, I found myself needing to send a PDF as an email attachment. The challenge was to generate the PDF on the backend. In our project, there were already means to achieve this in a microservice. The later return a PDF in the form of a byte array, given a payload containing all the information needed. This microservice utilizes two technologies to generate the final PDF: Thymeleaf (a template engine) and Puppeteer (which simulates the operation of a web page). Thymeleaf takes the data payload and an HTML template as input, written by the developer, and outputs pure HTML code. Then, the microservice sends this code to Puppeteer, which renders the HTML into a site and converts it into a PDF.
The implementation of our template in Thymeleaf presented some challenges during during development. A notable issue was the large file size, exceeding 1000 lines compared to the usual 100 to 200 lines of other templates managed by the microservice. Additionally, we encountered difficulties with the less readable syntax, especially in specific cases where we needed to set the width or enter numerical values directly into the CSS. These flaws made our template difficult to read and debug.
Despite these obstacles, Thymeleaf offers a distinct advantage with its HTML-centric approach. Navigating through questions and concerns was facilitated by the abundance of readily available solutions on the Internet, proving beneficial for resolving various issues.
ADR Preparation
Following the numerous problems encountered during my use of Thymeleaf, I wondered if using another template engine could make the implementation of my template simpler. Therefore, I wanted to test other template engines available in Java. After some research, I decided to test two other technologies: Jade4j (also known as Jade) and Freemarker. During my tests, I wanted to evaluate:
- Ease of use
- Documentation quality
- Template readability
- Available features
To test these different factors, I wanted to try coding the same dynamic PDF using each of the three template engines. Testing all three technologies on writing the same template aimed to compare them under very similar conditions to better highlight their differences. For the construction of the test PDF, I made a list of Thymeleaf features that I had used in my project and found important: the most basic functionality is to be able to pass text as a parameter(1), the ability to iterate over a list passed in the payload(2), and the ability to add style and/or a class conditionally(3). I then built my PDF to test all these features.
Creation of a Testing Tool
To start my ADR (Architecture Decision Record), I created a small GitHub repository containing a Java API. This API exposes a single route that returns a string corresponding to an HTML file. This route takes as input a JSON with the template data and a string specifying the template engine to use to generate the HTML. (you can see the repository here)
Thymeleaf
I then started writing my first template using Thymeleaf. This step proved to be very quick, as I already had good knowledge of Thymeleaf and easy access to the code to implement it. With the testing tool, I confirmed the feasibility of the PDF and I was able to confirm my initial impressions of the template engine: easy to use with good documentation, but slightly heavy syntax.
Ease of Use | Documentation Quality | Template Readability | Available Features |
---|---|---|---|
✅ | ✅ | ❌ | ✅ |
Jade4J
Once the Thymeleaf template was finished, I started my test for Jade. The first difficulty was retrieving the HTML format as a string to save it. I had trouble finding what existed in the documentation. These template engines are managed for sites directly in Java, which is not what interests me. After several searches, I tried to create a JadeModel and apply its render function:
public String generateHtml(DocumentParameter documentParameter) throws IOException{
JadeModel jadeModel = new JadeModel(documentParameter.getDocumentInputs());
return Jade4J.render(Jade4J.getTemplate("/Users/lucaspanier/Documents/panier/src/main/resources/templates/jade.jade"), jadeModel);
}
Victory, I managed to generate a string with my HTML containing the parameters I passed to it.
The second difficulty was that Jade templates do not resemble HTML at all, and I struggled to understand how it works: the available examples were not or poorly documented. Here, there are no opening and closing tags like in HTML, but the code hierarchy is done solely through indentation. However, we find the same tag names (div, h1, li), but this time they are just preceded by a dot. So the equivalent of this piece of HTML code:
<div>
<p> Paragraph text </p>
</div>
in Jade is:
.div
.p Paragraph text
Regarding styling, we can customize classes as in Thymeleaf, and to create a div with a class ‘header’, you just need to write ‘.header’ in the template, for example:
<style>
.header{
display : flex
}
.content{
color: black
}
</style>
.header
.content
At this stage of my test, I managed to find all the features available in Thymeleaf with Jade, and I could create the same page as with Thymeleaf.
Conclusion for Jade:
Ease of Use | Documentation Quality | Template Readability | Available Features |
---|---|---|---|
❌ | 🟠 | ✅ | ✅ |
Freemarker
For the third solution (Freemarker):
Initially, I encountered the same problem as with Jade in retrieving the HTML format as a string due to a lack of documentation. Here is the solution I found:
public String generateHtml(DocumentParameter documentParameter) throws IOException, TemplateException{
Configuration configuration = new Configuration(Configuration.VERSION_2_3_23);
configuration.setDefaultEncoding("UTF-8");
configuration.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
configuration.setLogTemplateExceptions(false);
final ClassTemplateLoader loader = new ClassTemplateLoader(DocumentParameter.class, "/templates");
configuration.setTemplateLoader(loader);
Template template = configuration.getTemplate("/free-maker-template.html");
StringWriter stringWriter = new StringWriter();
template.process(documentParameter.getDocumentInputs() , stringWriter);
return stringWriter.toString();
}
Once this step was completed, I realized that Freemarker was very similar to Thymeleaf. It closely resembles HTML: we use the same classic tags (div, h1, h2, etc.), and for conditional features, we need to use tags and add a ’#’ before keywords like switch, if, list. In terms of features, Freemarker has all the features tested previously in Thymeleaf and Jade, but the language is not well handled by IDEs (I tested on IntelliJ and VSCode): the Freemarker syntax is not recognized as HTML on switches or for each loops. Finally, regarding the documentation, I found Freemarker documentation more difficult to find and understand than the previous two.
Errors on IntelliJ :
Errors on VSCode :
Conclusion for Freemarker:
Ease of Use | Documentation Quality | Template Readability | Available Features |
---|---|---|---|
🟠 | ❌ | ❌ | ✅ |
Conclusion
In conclusion, although all three tools I tested offer the same features I needed, I have a preference for Thymeleaf and Jade. For me, Freemarker is a less well-documented and less ergonomic version of Thymeleaf. As for differentiating Thymeleaf from Jade, I think Thymeleaf is really suitable for small templates with low complexity because the learning curve at the outset is low. However, for more complex and larger projects, Jade does better thanks to its cleaner syntax which allows the logic of the code to be better highlighted.
Criteria | Thymeleaf | Jade4J | Freemarker |
---|---|---|---|
Ease of Use | ✅ | ❌ | 🟠 |
Documentation Quality | ✅ | 🟠 | ❌ |
Template Readability | ❌ | ✅ | ❌ |
Available Features | ✅ | ✅ | ✅ |