Platinum Partner
java

Using StringTemplate: Part 1 'An Introduction to StringTemplate'

Please note: I put forth SQL examples because they can be short and are easy to understand. As other have pointed out it is not advisable to build SQL with Strings, regardless of the technique used.

To quote the StringTemplate home page: “StringTemplate is a Java template engine for generating source code, web pages, emails, or any other formatted text output.”

Great, but what is a “template engine”?
          A template engine (also known as a template processor or a template parser) is a software component that is designed to combine one or more templates with a data model to produce one or more result documents (Wikipedia). To you and me that means that a template engine is an alternate way to generate complicated text. One that I feel is particularity useful. Before we dive into that, lets take a look at a few examples of traditional String construction in Java.

First we have the trusty old “+” operator.

String message = "Hello" + " World"; 

While convenient for small concatenations. It becomes a real pain when the embedded variable count of the amount of text increases.   

    String strSQL = "UPDATE customers SET customerName='" + name
+ "', customerAddress='" + address
+ "', customerEmail = '”+ email + "
+ "customerNumber = " + phone
+ " customerPurchase = " + purchase
+ "' WHERE id=" + 12;

String new419 = "Hello "
+ "Dear, " + name + ", \n"
+ "Permit me to inform you of my desire of "
+ "going into business relationship with you. "
+ "I have the believe you are a reputable "
+ "and responsible and trustworthy person \n"
+ "I can do business with from the little"
+ "information so far I gathered about you "
+ "during my search for a partner and by matter "
+ "of trust I must not hesitate to confide "
+ "in you for this simple and sincere business. ";

Next we have StringBuilder. In general it's considered a better practice to use StringBuilder because of it's performance profile.

    StringBuilder sqlBuilder = new StringBuilder(
"UPDATE customers SET customerName='").append(name).append(
"', customerAddress='").append(address).append(
"', customerEmail = '").append(email).append(
"', customerNumber = '").append(phone).append(
"', customerPurchase = '").append(purchase).append(
"' WHERE id=").append(12);

Unfortunately it doesn't make building up a string significantly easier. 

Finally we have formatted text.

// Explicit argument indices may be used to re-order output.
String.format("%4$2s %3$2s %2$2s %1$2s", "a", "b", "c", "d");
>> d c b a

// Optional locale as the first argument can be used to get
// locale-specific formatting of numbers. The precision and width can be given
// to round and align the value.

String.format(Locale.FRANCE, "e = %+10.4f", Math.E);

>> e = +2,7183

// The '(' numeric flag may be used to format negative numbers with
// parentheses rather than a minus sign. Group separators are
// automatically inserted.

String.format("Amount gained or lost since last statement: $ %(,.2f",balanceDelta);

>> Amount gained or lost since last statement: $ (6,217.58)

Format is powerful but only scales up to, at most, a handful of parameters. This is not because there is some programmatic limit to the Format class, but more one of practicality. Tracking a hundred parameters by their index would be quite challenging.

Templates, a better way.

A template is simply a document with “placeholders” in it. These “placeholders” are expressions that tell the template engine where to put data.  All (okay most) white space and line feed characters are respected. This also has the nice benefit of separating the formatting (view) from the data. Here is a simple single line example :

 

     StringTemplate query = new StringTemplate(
"UPDATE customers SET customerName='$customer$'," +
" customerAddress='$address$' WHERE id=$id$");

query.setAttribute("customer", "Frank");
query.setAttribute("address", "1313 Mocking Bird Lane");
query.setAttribute("id", "4453");

System.out.println(query);

Output:


    UPDATE customers SET customerName='Frank', customerAddress='1313 Mocking Bird Lane' WHERE id=4453 

As you can see “placeholders” are delimited by $...$ (or <...> if you so choose). In this way it is reminiscent of variable substitution in languages like PHP or bash. The name inside the delimiters is used to look up the correct piece of data. Having names is important for maintaining readability. It also allows data to be pushed into the template in any order. This was a single line example. When you get to multi-line text you will probably want to use a template file. A template file is a plain text document that contains the fully formatted version of your desired output. $...$ attributes are placed thought the document to indicate parts you want replaced later by StringTemplate.

Example template file (spam-419.st):

From Address $from_addr$
To Address $to_addr$
Dear $to$,
    Permit me to inform you of my desire of going into business relationship with you. I have
    the believe you are a reputable and responsible and trustworthy person I can do business
    with from the little information so far I gathered about you during my search for a partner
    and by matter of trust I must not hesitate to confide in you for this simple and sincere business
.
...
Best Regards, $from$

Populating this template involves loading a StringTemplateGroup and using that to create an instance of your StringTemplate.

 

    StringTemplateGroup templateGroup = new StringTemplateGroup("spam group", "templates");
StringTemplate spam419 = templateGroup.getInstanceOf("spam419");
spam419.setAttribute("to", "Collin");
spam419.setAttribute("to_addr", "collin@bugmenot.com");
spam419.setAttribute("from", "Ima Spammer");
spam419.setAttribute("from_addr", "ima.spammer@spammers-paradise.com");

System.out.println(spam419.toString());

The StringTemplateGroup constructor in the code above takes two parameters. The first is a "group name". In this example it is not really important, feel free to use anything you like. The second is very important. This is the location of a directory (folder) that contains the template files you wish to load. In this example I am using a relative path. Relative to where I'm executing this code I expect to see a directory called "templates". The getInstanceOf() method takes the name (without the .st extension) of the that template file to be loaded. In this case I'm attempting to load "spam419.st".

From Address ima.spammer@spammers-paradise.com
To Address collin@bugmenot.com
Dear Collin,
    Permit me to inform you of my desire of going into business relationship with you. I have
    the believe you are a reputable and responsible and trustworthy person I can do business
    with from the little information so far I gathered about you during my search for a partner
    and by matter of trust I must not hesitate to confide in you for this simple and sincere business
.
...
Best Regards, Ima Spammer

I encourage you to experiment with this template. I think you will find adding or removing lines is trivial. Changing white space in the template is trivial. Even adding new attributes (placeholders) is straight forward. StringTemplate is a powerful tool that I can't hope to cover in just one blog post. For those who are chomping at the bit to learn more I'd recommend reading the official StringTemplate documentation which is a fantastic resource. 

Have fun,
Collin

 

From http://weblogs.java.net/blog/aberrant/archive/2010/05/25/using-stringtemplate-part-1-introduction-stringtemplate

{{ tag }}, {{tag}},

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}
{{ parent.authors[0].realName || parent.author}}

{{ parent.authors[0].tagline || parent.tagline }}

{{ parent.views }} ViewsClicks
Tweet

{{parent.nComments}}