---
title: jinjava - a jinja for your java
description: Jinjava is a new templating engine for Java, implementing the Jinja syntax.
image: https://product.hubspot.com/hubfs/Jinjava-1.png
---

[Engineering](https://product.hubspot.com/blog/topic/engineering)

# jinjava - a jinja for your java

[ Jared Stehler ](https://product.hubspot.com/blog/author/jared-stehler)

 on Dec 18, 2014

**TL;DR:** HubSpot is [open-sourcing](https://github.com/HubSpot/jinjava) its fast, Jinja-compatible templating language runtime for Java.

HubSpot's Content Optimization System (COS) was originally developed in python, and the templating engine chosen to power it was [Jinja](http://jinja.pocoo.org/docs/dev/). Jinja provides a robust and powerful foundation in which to craft page templates, in a syntax derived from django templates. While python was a fine choice at the start, and allowed us to rapidly iterate on the COS, we started to run into growing pains and scalability issues with python and django. Over the past year, we've been reimplementing parts of the system in Java.

While there are a multitude of mature and widely used Java templating engines out there, we realized rather quickly that it wouldn't be feasible to try and migrate our existing customers' templates to a different language; we've historically allowed our customers to use all of the language constructs, filters, tags, etc.

In searching for an off-the-shelf java implementation, the closest we found was an old implementation of django templating, [jangod](https://code.google.com/p/jangod/). This proved to be a good start to get the ball rolling with the COS renderer port, but there were many gaps which needed to be filled in order to bring us up to where we needed to be. After the first 100 commits or so, we ended up forking the project and pushing it to where we needed it to be, and [Jinjava](https://github.com/HubSpot/jinjava) was born!

### A Client-focused Templating Library

Perhaps differently than other templating libraries for Java, Jinjava sports an API which reflects our application's use of customer-created free form templates. This means that when you render a template, you can get as a result a listing of any errors encountered during the render complete with template line numbers.

> ```
> Jinjava jinjava = new Jinjava();RenderResult result = jinjava.renderForResult(template, context);for(TemplateError error : result.getErrors()) {    renderError(error.getSeverity(), error.getMessage(),                 error.getLineNumber());}
> ```

### Extensibility

There are four extension points in Jinjava where you can add custom functionality:

#### Tags

Tags are a standard construct in any templating language; in Jinjava they have a declaration syntax which is similar to mustache:

> ```
> {% timestamp %}{% if my_var > 0 %} ... {% endif %}
> ```

Adding new tags is a simple process; extend from `com.hubspot.jinjava.lib.tag.Tag`, and register the tag with the Jinjava instance before you render anything with it. Tags can have inner content, and have the ability to modify the template context during execution, doing things like setting / updating variables, etc.

> ```
> public class TimestampTag implements Tag {  @Override  public String getName() { return "timestamp"; }  @Override  public String getEndTagName() { return null; }  @Override  public String interpret(TagNode tagNode,                           JinjavaInterpreter interpreter)   {    return new String(System.currentTimeMillis());  }}
> ```

register the tag with the global context, so it'll be available in all render operations on that jinjava instance:

> ```
> Jinjava jinjava = new Jinjava();jinjava.getGlobalContext().registerTag(new TimestampTag()); 
> ```

#### Filters

Filters are functions which can be used in expressions, invoked via a "pipe" operator syntax signifying their purpose of translating/transforming a prior value:

> ```
> {{ my_val | uppercase | split(',') }}
> ```

You register filters in the same way as tags above. A filter's signature includes the "affected" object, as well as a parsed list of any arguments passed in:

> ```
> public class ConcatFilter implements Filter {  @Override  public String getName() { return "concat"; }  @Override  public Object filter(Object var,                        JinjavaInterpreter interpreter,                       String... args)  {    String addend = args[0];    return var.toString() + addend;  }}
> ```

#### Expression Tests

An expression test is a special type of function invoked via the 'is' operator:

> ```
> public class IsEvenExpTest implements ExpTest {  @Override  public String getName() {    return "even";  }  @Override  public boolean evaluate(Object var,                           JinjavaInterpreter interpreter,                          Object... args) {    if(var == null || !Number.class.isAssignableFrom(var.getClass())) {      return false;    }     return ((Number) var).intValue() % 2 == 0;  }}
> ```

#### Functions

As you might expect, you can define raw functions which can be used in expressions. In their simplest form, Jinjava functions are public static java functions which you register with an instance of ELFunctionDefinition:

> ```
> register(new ELFunctionDefinition("fn", "list", Lists.class,                                   "newArrayList", Object[].class));
> ```

which can then be used in a template expression:

> ```
> {% set mylist = fn:list() %}
> ```

Additionally, we created a special proxy wrapper class so that we could define template functions which have access to Guice-injected instances like DAO's and API services: [InjectedContextFunctionProxy](https://github.com/HubSpot/jinjava/blob/master/src/main/java/com/hubspot/jinjava/lib/fn/InjectedContextFunctionProxy.java). You can use the static function defineProxy(..) on this class to wrap an object instance with a static invocation wrapper, so it can be invoked in a template without a target object.

### Performance & Benchmarks

We did set up some performance benchmarks, to relatively compare ourselves to similar libraries on other platforms. Generally speaking, the overhead of the rendering engine is such that the likeliest bottleneck you're apt to have will come from custom tags which do time-intensive things like pull data from remote service APIs and such. With that said, here are our very unscientific results, with benchmarks from each compared engine ported to Jinjava (run on MacBook Pro 2.6 Ghz, OSX Yosemite 10.10.1):

| **[Jinjava vs. Liquid](https://github.com/HubSpot/jinjava/blob/master/benchmark/src/main/java/com/hubspot/jinjava/benchmarks/liquid/LiquidBenchmark.java)** | ****Liquid (@e2f8b28) on Ruby (****2.0.0p481) | **Jinjava** |
| --- | --- | --- |
| parse | 21.814 runs/s | **1383.319 runs/s** |
| parseAndRender | 14.840 runs/s | **627.996 runs/s** |

 

| [**Jinjava vs. Jinja2**](https://github.com/HubSpot/jinjava/blob/master/benchmark/src/main/java/com/hubspot/jinjava/benchmarks/jinja2/Jinja2Benchmark.java) | **Jinja2 (@85820fc) on Python (2.7.6)** | **Jinjava** |
| --- | --- | --- |
| RealWorldish Benchmark | 1387.3108 runs/s | **1643.407 runs/s** |

### Conclusion

Jinjava has served us well so far, easing our transition from python to java. I think it can hold its own against similar rendering engines out there. It powers the HubSpot COS, what can it do for you?

 

### References

- [Jinjava Project Page](https://github.com/HubSpot/jinjava)
- [HubL Developer Docs](https://designers.hubspot.com/docs/markup/hubl-syntax-reference)
- [jinja reference](http://jinja.pocoo.org/docs/)
- [Liquid template engine by Shopify](https://github.com/Shopify/liquid/wiki/Liquid-for-Designers)
- [Django template engine](https://docs.djangoproject.com/en/dev/topics/templates/)
- [Mustache JS templates](http://mustache.github.io/)

 

 

[Share on Twitter](https://twitter.com/intent/tweet?url=https%3A%2F%2Fproduct.hubspot.com%2Fblog%2Fjinjava-a-jinja-for-your-java)[Share on Facebook](https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fproduct.hubspot.com%2Fblog%2Fjinjava-a-jinja-for-your-java)[Share via email](mailto:info@example.com?&subject=&body=https%3A%2F%2Fproduct.hubspot.com%2Fblog%2Fjinjava-a-jinja-for-your-java)[Share on LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fproduct.hubspot.com%2Fblog%2Fjinjava-a-jinja-for-your-java)

## Recommended Articles

<https://product.hubspot.com/blog/email-templates>

[Engineering](https://product.hubspot.com/blog/topic/engineering)

## [How HubSpot Delivers Email Templates to 900K+ Accounts](https://product.hubspot.com/blog/email-templates)

 Back in July, HubSpot released free email marketing tools on top of our already free CRM. As part of these email tools, every portal gets 20 ...

[ Mitchell Katz (He/Him) ](https://product.hubspot.com/blog/author/mitchell-katz)

 on Oct 31, 2019

<https://product.hubspot.com/blog/upgrading-to-java-8-at-scale>

[Engineering](https://product.hubspot.com/blog/topic/engineering)

## [Upgrading to Java 8 at Scale](https://product.hubspot.com/blog/upgrading-to-java-8-at-scale)

 The vast majority of HubSpot's backend code is written in Java. We have over 350 separate Java deployables including Dropwizard APIs, Kafka ...

[ Jonathan Haber (He/Him) ](https://product.hubspot.com/blog/author/jonathan-haber)

 on Apr 6, 2015

<https://product.hubspot.com/blog/the-fault-in-our-jars-why-we-stopped-building-fat-jars>

[Engineering](https://product.hubspot.com/blog/topic/engineering)

## [The Fault in Our JARs: Why We Stopped Building Fat JARs](https://product.hubspot.com/blog/the-fault-in-our-jars-why-we-stopped-building-fat-jars)

 HubSpot’s backend services are almost all written in Java. We have over 1,000 microservices constantly being built and deployed. When it comes time ...

[ Jonathan Haber (He/Him) ](https://product.hubspot.com/blog/author/jonathan-haber)

 on Jun 16, 2016

## Join our subscribers

Sign up here and we'll keep you updated on the latest in product, UX, and engineering from HubSpot.

[Subscribe to the newsletter

](https://product.hubspot.com/blog/jinjava-a-jinja-for-your-java#subscription-popup)

[Back](https://product.hubspot.com/blog/jinjava-a-jinja-for-your-java#)

## Get Connected

The latest engineering, UX, and product news from the HubSpot Product Blog, straight to your inbox.

Next

Not using [HubSpot](https://www.hubspot.com/) yet?

Search Term:

** Search HubSpot.com ** Search the blog

Load more