Collin Fagan is a Sr. Software Engineer at NAVTEQ working on next generation map building software. He holds a BS in Computer Science from the Rochester Institute of Technology. Collin has worked in the Map, Medical, Produce Warehousing and Telecommunications industries on a wide assortment of projects ranging from customized Linux thin clients to highly concurrent telecommunications control systems. Collin has posted 13 posts at DZone. View Full User Profile

Using StringTemplate: Part 1 'An Introduction to StringTemplate'

05.26.2010
| 6510 views |
  • submit to reddit

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

Published at DZone with permission of its author, Collin Fagan.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags:

Comments

Gabor Farkas replied on Wed, 2010/05/26 - 3:52am

About string constants:

  • "a" + "b" + "c" actually compiles to a constant "abc" (with eclipse at least)
  • A simple expression of string concatenation (eg: "Hello "+name+", your credit is "+credit+".") compiles to using one single StringBuilder. Explicitly creating a StringBuilder in your code comes handy when you have some iteration.

And please be aware that using this kind of templates for creating database queries is tipically a bad idea (sql injection). For notifications, email templates and such things, it's perfect.

Collin Fagan replied on Wed, 2010/05/26 - 1:32pm in response to: Gabor Farkas

SQL Injection: You are absolutely correct. I was more concerned with using short understandable examples then best practices. I'm going to put a note at the top.

 

Also I'd like to thank the Dzone member who re-posted my java.net articel. I was not sure I was going to have the time to post it here all nice and formatted. 

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.