Support & Downloads

Izymes builds easy-to-use apps for Atlassian applications that boost your productivity, free you from performing repetitive tasks inside Confluence, Jira and Bitbucket and enable you to use your time for what you do best – YOUR job.

Book a Demo

Interested in a 1-on-1 demonstration of Izymes’s products?
Here we will walk you through;

• All features and benefits of the product you are interested in trying.
• How to set up the account and configure the settings.
• Other tips, tricks and best practices.

It will also give us time to answer any questions you may have, or perhaps you just want to have a chat, we love a good chat.
You can schedule a time on the Calendly link below. Talk soon!

Contact Info
HQ Southport
Queensland, Australia
[email protected]
Follow Us

A (very) Simple Template Renderer for Java

When we introduced customisable email subjects for Reminders for Bitbucket I needed a template renderer that

  • takes a user-defined string based template
  • references template placeholders and resolves their values in the render context
  • does not depend on any heavy weight templating library

Let’s assume the end-user would enter a email subject template like

This is PR #{pullRequest.id} from {pullRequest.author.user.name}

Placeholders are marked by {} and reflect the Java object’s hierarchy. Yes – reflect – is the key word here. The impatient may find a ready to go class on Github.

A (very) Simple Expression Parser

To identify the placeholders in the template we use a regex pattern matching like

List<String> expressions = Lists.newArrayList();
Matcher m = Pattern.compile("\\w*\\{(.*?)\\}").matcher(subject);
while (m.find()) {
    String expression = m.group(1);
    expressions.add(expression);
}

Finding the Placeholder Values

The render context holds all the Java objects needed to resolve the placeholder expression values and turn them into Strings.

Stream<String> values = expressions.stream()
 .map(e -> resolve(context, getMethods(e)))
 .map(v -> v+"");

Resolving Expressions

As mentioned above Java Reflection is used to traverse the render context objects via their getter and setter methods. First a list of methods is extracted from the placeholder expression.

Arrays.stream(expression.split("\\."))
        .map(m -> "get" + m.substring(0, 1).toUpperCase() + m.substring(1))

For example {pullRequest.id} would be resolved to [getPullRequest(), getId()], and  {pullRequest.author.user.name} would be resolved to [getPullRequest(), getAuthor(), getUser(), getName()].

The obtained list of methods will then be called recursively on the render context object using Java reflection in order to obtain the target value.

private Object resolve(Object o, List<String> methods)  {
    if (methods.size() == 0) return o;

    Object result = null;
    try {
        Method m = o.getClass().getMethod(methods.get(0));
        result = m.invoke(o);
    } catch (NoSuchMethodException e) { ... }
    methods.remove(0);
    return resolve(result, methods);
}

Rendering the Result

Now that we have a list of values that substitute their placeholders let’s rewrite the template into a format String

String format = templateString.replaceAll("\\{.*?\\}", "%s");

… and use String.format() to render the final result

String.format(format, values.toArray());

Get the complete class from Github.