Use Apache Velocity as template engine
Context and Problem Statement
We need to choose a template engine for custom export filters and AI features.
A discussion of template engines was also in one of the JabRef repos.
A discussion was raised on StackOverflow “Velocity vs. FreeMarker vs. Thymeleaf”.
Decision Drivers
- It should be fast.
- It should be possible to provide templates out of
String
s (required by the AI feature). - It should have short and understandable syntax. Especially, it should work well with unset fields and empty
Optional
s.
Considered Options
- Apache Velocity
- Apache FreeMarker
- Thymeleaf
- Handlebars (Mustache)
- Jinja
Decision Outcome
Chosen option: “Apache Velocity”, because “Velocity’s goal is to keep templates as simple as possible” (source). It is sufficient for our use case. Furthermore, Apache Velocity is lightweight, and it allows to generate text output. This is a good fit for the AI feature.
Update from 01.10.2025: more promising options were added (Handlebars and Jinja), but the final decision was not discussed and updated.
Pros and Cons of the Options
Apache Velocity
- Main page: https://velocity.apache.org/.
- User guide: https://velocity.apache.org/engine/devel/user-guide.html.
- Developer guide: https://velocity.apache.org/engine/devel/developer-guide.html.
Example:
You are an AI assistant that analyses research papers. You answer questions about papers.
Here are the papers you are analyzing:
#foreach( $entry in $entries )
${CanonicalBibEntry.getCanonicalRepresentation($entry)}
#end
- Good, because supports plain text templating.
- Good, because it is possible to use
String
as a template. - Good, because it has simple syntax, and it is designed for simple template workflows.
- Good, because it has a stable syntax (source).
- Bad, because it is in maintenance mode.
- Bad, because removed from Spring 5.0.1
Apache FreeMarker
- Main page: https://freemarker.apache.org/index.html.
- User guide: https://freemarker.apache.org/docs/dgui.html.
- Developer guide: https://freemarker.apache.org/docs/pgui_quickstart.html.
Example:
You are an AI assistant that analyzes research papers. You answer questions about papers.
Here are the papers you are analyzing:
<#list entries as entry>
${CanonicalBibEntry.getCanonicalRepresentation(entry)}
</#list>
- Good, because supports plain text templating.
- Good, because it is possible to use
String
as a template. - Good, because in active development.
- Good, because it is powerful and flexible.
- Good, because it has extensive documentation (source).
- Neutral, because it has received some API and syntax changes recently (source).
- Neutral, because FreeMarker is used for complex template workflow, which we do not need in JabRef.
Thymeleaf
- Main page: https://www.thymeleaf.org/.
- Documentation: https://www.thymeleaf.org/doc/tutorials/3.1/usingthymeleaf.html.
Example:
You are an AI assistant that analyzes research papers. You answer questions about papers.
Here are the papers you are analyzing:
[# th:each="entry : ${entries}"]
[(${CanonicalBibEntry.getCanonicalRepresentation(entry)})]
[/]
- Good, because supports plain text templating.
- Good, because it is possible to use
String
as a template. - Good, because it has several template modes, that helps to make HTML, XML, and other templates.
- Good, because it is powerful and flexible.
- Neutral, because the API is a bit more complex than the other options.
- Bad, because the syntax is more complex than the other options. Especially for text output.
Handlebars (Mustache)
Because Handlebars and Mustache have similar syntax, and library mentioned below supports both languages, we decided to merge Handlebars and Mustache into one option.
- Main page: https://handlebarsjs.com/.
- Java port repository and developer guide: https://github.com/jknack/handlebars.java.
- User guide: https://handlebarsjs.com/guide/.
Example:
You are an AI assistant that analyses research papers. You answer questions about papers.
Here are the papers you are analyzing:
- Good, because supports plain text templating.
- Good, because it is possible to use
String
as a template. - Good, because it is powerful and flexible.
- Good, because it has a simple API.
- Neutral, as custom functions needs to be added manually. You cannot pass an ordinary Java object and use it as you want.
Jinja
- Main page: https://palletsprojects.com/projects/jinja/.
- Java port repository and developer guide: https://github.com/HubSpot/jinjava.
- User guide: https://jinja.palletsprojects.com/en/stable/templates/.
You are an AI assistant that analyses research papers. You answer questions about papers.
Here are the papers you are analyzing:
- Good, because supports plain text templating.
- Good, because it is possible to use
String
as a template. - Good, because it is powerful and flexible. It supports extension and inheritance.
- Good, as it is widely used and has great tooling support (linters, formatters, etc.).
- Good, as it has easy to read syntax.
- Neutral, as it was developed for web and Python, not for Java.
- Neutral, as the Java port is quite young (in comparison to other options).
- Neutral, as custom functions needs to be added manually. You cannot pass an ordinary Java object and use it as you want.
More Information
As stated in the template discussion issue, we should choose a template engine, and then slowly migrate previous code and templates to the chosen engine.
Other template engines are discussed at https://www.baeldung.com/spring-template-engines, especially #other-template-engines
. We did not find any other engine there worth switching to.