Category Archives: Velocity

Embedding files and/or templates within templates using Velcocity

We can embed a file or other templates within Velocity templates – this is obviously useful for reusing snippets of code/text or whatever in more than file. We still need to create the context mappings for all the template file that form out overall template – in other words we supply the mappings the container template and all of the embedded templates.

To embed a template we simply use the #include or #parse directives. #include is used to pull in a template or file without transforming it using the template engine, i.e. any variables etc. will not be transformed or rendered by Velocity whereas #parse will transform any Velocity variables or code.

Taking the template (template.txt.vm) from my previous post, which looked like this

Hello $name,

This is a $template_name template.

we might break this template into the following two templates

salutation.txt.vm

Hello $name,

and template.txt.vm becomes

#parse("templates/salutation.txt.vm")

This is a $template_name template.

This will result in the combined and transformed template.

Using the Velocity template engine

Velocity is a template engine written for Java. It allows us to take files (or strings) with embedded Velocity Template Language (VTL) code and transform the files (or strings) based upon supplied values.

Let’s create a simple template file (by default we use the extension .vm and a good convention is to append it to the original extension file type, so you know what type of file you’re transforming) then we’ll use Velocity to transform the file.

We’ll create a standard Maven layout project

  • From IntelliJ create a new project and select Maven
  • In the src/test folder add a new directory names resources
  • Mark the directory as test resources
  • Add a folder to resources named templates
  • Add the file template.txt.vm

My template.vm looks like this

Hello $name,

This is a $template_name template.

As you’ve probably guessed the $ prefix denotes a variable which we will supply to Velocity.

The first thing we need to do is create the Velocity engine and then set it up to allow us to load our files from the resources folder, here’s the code for this

VelocityEngine velocityEngine = new VelocityEngine();
velocityEngine.setProperty(
   "resource.loader", 
   "file");
velocityEngine.setProperty(
   "file.resource.loader.class", 
   "org.apache.velocity.runtime.resource.loader.FileResourceLoader");
velocityEngine.setProperty(
   "file.resource.loader.path", 
   "src/test/resources");

Next up we create a VelocityContext which we use to supply our mappings to the variable names used within the template file. We do not include the $ when supplying the variable name. We simply supply key value pairs, where the key is a String which represents the variable name and the value is what we want to replace it with (this is an Object which can be more complex than just a String). For this example our value will just be a String, so we have the following

VelocityContext velocityContext = new VelocityContext();
velocityContext.put("name", "PutridParrot");
velocityContext.put("template_name", "MyPutridParrotTemplate");

Note: If we do not add a context mapping then the result will be the original $variable_name, unchanged.

Finally, we want to actually “merge” (as Velocity calls the process) our context against the template and at the same time we’re going to convert the resultant “merged” template into a string

StringWriter writer = new StringWriter();
Template template = velocityEngine.getTemplate("templates/template.txt.vm");
template.merge(velocityContext, writer);

// to prove it worked...
System.out.println(writer.toString());

Running the above code we will get the output (as you would expect)

Hello PutridParrot,

This is a MyPutridParrotTemplate template.

Taking things a little further

As mentioned previously the value stored within the context is an Object, so we can store an array of values if we want.

Let’s assume we have the following template file

Hello $name,

My templates

#foreach( $t in $template_name)
    * $t
#end

As you can see the VTL supports foreach loops, so if we change the code that assigns the template_name to the context to look like this

ArrayList<String> list = new ArrayList<>();
list.add("Putrid");
list.add("Parrot");

velocityContext.put("template_name", list);

Our output will now be

Hello PutridParrot,

My templates

    * Putrid
    * Parrot

Take a look at the VTL reference for more options.

And finally

Finally for this post, it’s not unusual to have a string that represents the template, for example, maybe we get our templates from a web service or just load from another file location into memory.

Here’s the full code for this

String templateString = "Hello $name,\n\nThis is a $template_name template.";

RuntimeServices runtimeServices = RuntimeSingleton.getRuntimeServices();
StringReader reader = new StringReader(templateString);
SimpleNode node = runtimeServices.parse(reader, "Velocity Template");

VelocityContext velocityContext = new VelocityContext();
velocityContext.put("name", "PutridParrot");
velocityContext.put("template_name", "MyPutridParrotTemplate");

StringWriter writer = new StringWriter();
Template template = new Template();
template.setRuntimeServices(runtimeServices);
template.setData(node);
template.initDocument();

template.merge(velocityContext, writer);

// to prove it worked...
System.out.println(writer.toString());

The key differences are how we create the SimpleNode and then create the Template.