StringTemplate1 is a Java template engine for generating formatted text, particularly used for code generation which is what I set out to achieve through this.

Setting up

In build.sbt

libraryDependencies += "org.antlr" % "ST4" % "4.0.8"

In pom.xml

<dependency>
  <groupId>org.antlr</groupId>
  <artifactId>ST4</artifactId>
  <version>4.0.8</version>
</dependency>

To check if everything is loaded and runs smoothly, try this example

import org.stringtemplate.v4._

val hello = new ST("println(<name>)"
hello.add("name", "hello")

val output = hello.render()
println(output) // println(hello)

Creating templates

In an actual use-case, you’re likelier to use templates as resource files to isolate it from the codebase. StringTemplate supports two modes of reading templates — as individual template files or as a directory containing a collection of template files.

A typical template group file would look like this -

foo(bar, baz) ::= <<
val output = <bar>(<baz>)
>>

Which would be invoked from Java/Scala -

val template = new STGroupFile(<location-to-template-file>)
val builder = template.getInstanceOf("foo")
builder.add("bar", "println")
builder.add("baz", "4")

val output = builder.render()
println(output) // val output = println(4)

Overriding delimiter

The default template delimiter is <..> by default. You could always change that by adding an additional argument while creating the template object -

new STGroupFile(<location-to-template-file>, <startChar>, <stopChar>)

Using custom classes

You could pass a custom class object instead of a string param -

# custom class
import scala.beans.BeanProperty

// required to generate getters which is used by StringTemplate to lookup values
case class Bar(@BeanProperty name: String)

# template
foo(bar) ::= <<
println("<bar.name>")
>>

# invocation
val template = new STGroupFile(<location-to-template-files>)
val builder = template.getInstanceOf("foo")
builder.add("bar", Bar("baz"))

val output = builder.render()
println(output) // println("baz")

Setting defaults

Refer to2 for further use-cases like injecting data aggregate attributes and applying templates to attributes