Using StringTemplate: Part 1 'An Introduction to StringTemplate'
Join the DZone community and get the full member experience.
Join For FreePlease 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
Opinions expressed by DZone contributors are their own.
Comments