Speed and memory
ST v4 seems to be about 2x faster than v3 when there's no memory pressure / GC thrashing. With memory constraints, ST v4 is much faster because it seems to use less memory. This data comes from upgrading ANTLR to use ST v4.
Migrating to v4 from v3
In general, migrating to v4 is straightforward. The biggest difference is that the names of the types have changed (I got tired of typing StringTemplateGroup all the way out
) as well as the package. Instead of base package org.stringtemplate, we use org.stringtemplate.v4.
- StringTemplate -> ST
- StringTemplateGroup -> STGroup, STGroupFile, or STGroupDir. References to
new StringTemplateGroup(directory)should becomenew STGroupDir(directory). References tonew StringTemplateGroup(new FileReader("file.stg"))should becomenew STGroupFile("file.stg"). - We pass in delimiter start and stop characters to the constructor of groups rather than passing in AngleBracketTemplateLexer.class. The default delimiters are angle brackets
<...>instead of dollar signs$...$. - setAttribute() -> add(). This makes it clear that we are adding rather than resetting attribute values. The semantics of the same except that we can add null values.
- There is no group header in group files but they're ignored for backward compatibility. Instead, use (possibly multiple)
import "filename.stg"orimport "dirname"orimport "template.st". - All explicit and implicit references to ST.toString() become calls to render(). It was difficult to debug templates because the debugger keeps calling toString to display objects. Also, it's better to be explicit that we are rendering a template string. There are a lot of implicit conversions of templates to strings. For example,
should be
- All templates require formal arguments unless you use constructor
new ST("a template"). So, a template file looks likeinstead of just[<x>]. - The syntax inside templates is the same except that there is no need for
...argument that said ``pass through outer arguments.'' - There is no implicit
itorattrattribute during generation now. convert<names:{<it>}>to<names:{n | <n>}>. If you use<names:foo()>and foo looks like:then convert itST will automatically pass in iterated value as the first argument (as it would do in v3). - The functionality of existing templates should be the same except that iterating across a Map is on the keys not values for v4. In v3, it iterated across the values. We had to use <aMap.keys:{...}> to iterate across the keys. This is the only change that could be painful because of the dynamic typing nature of ST. There's no static tool to find these occurrences.
- The only other thing is that you might notice some differences in the whitespace handling.
New Functionality
- STViz template visualizer; setting STGroup.debug creates DebugST objects not ST and tracks which Java code sets which attributes and/or creates templates. You need to set the debug flag in order to use the visualizer.
- multiple template group inheritance using
import - Added ModelAdaptors, an object that knows how to convert property references to appropriate actions on a model object. Given <a.foo>, we look up foo via the M adaptor if "a instanceof(M)".
- For <if(...)> conditionals, you can use && || conditional operators instead of nested IF statements
strlen,trim, andreversefunctions for lists- predefined DateRenderer and StringRenderer (understands formats upper, lower, cap, url-encode, xml-encode) objects.
- v4 has <%...%> template definitions that are like <<..>> except that they ignore all new lines. This is very convenient for complicated templates that need to be broken up for easy viewing but that shouldn't have newlines in the output.
- Added ST.format methods for use in general Java code.
Yields:
- \n in a template becomes \r\n or \n in output depending on platform.
We can always use \n in templates. To force \r\n on unix, though, we can still
create a writer: - renderers know locale optionally; only one method in renderer now with all args
- The default file encoding for templates and template groups is UTF-8.
Differences
Major
- template arguments can be named or passed by position at the call site as we would in Java. For example, given a template t with two arguments, we can use<t("a","b")> to pass two strings instead of <t(first="a", last="b")>. In v3, you would get into weird situations where you would have to do <t(a=a, b=b)>. now we can say <t(a,b)>.
- Map iteration is on keys not values for v4
- no "it" iteration value
- groups:
- Unify groups; groups are just template files cat'd together
- STGroup not StringTemplateGroup, STGroupDir, STGroupFile
- no group header in group files but multiple import "filename.stg" or import "dirname"
- render() not toString()
- v4 does not support template interfaces
Minor
- We can't pass arguments to the templates in map operations like this:
<names:foo("hi")>. - default args can see other args:
t(x,y={<x:{s|<s><z>}>},z="foo") ::= <<...>> - allows hasXXX property method in addition to the getXXX and isXXX.
- <a.b> for missing b is no longer an error
- templates do not have listeners; only groups have listeners
- renderers are per group and the group the interpreter feeds off of native group. Renderers in v4 now operate on class subtrees instead of exact types. Renderer associated with type t works for object o if
So it works if o is subclass or implements t.
- Can only have 65535 char in any one template (instr operands are shorts and write instruction refs back into source template pattern).
- allows <{...}> so we can add strip/filter/format option to ignore WS
- reset() doesn't exist anymore. Getting an instance of a template provides a "resetted" one.
- missing vs empty; null in list and false-IF are like missing; empty is "" or <else><endif> clause
- null values for attr allowed; st.add("name", null). same as missing.
it's added to list if we add other values afterwards. same
now as sending in list of null - arg "..." is a string (noninterpreted) and {...} is an anon template that allows full nesting etc...
- can't do separator=names:{..} (no map ops in option expr)
but can do optionname={...} - i, i0 don't propagate in dyn scoping
- setting attr i or i0 has no effect; they go 1..n 0..n-1 anyway
- <...> by default
- ".." means string literal, {...} and <<...>> are templates; e.g., in map defs
- change doc to say dict not map for dicts in group files.
- for dictionaries: render any key to a string for lookup; m.(key)
- trim just one WS char from start of multi-line templates, not all whitespace; none at end; no longer needed since we use formal args in .st files now. "..." don't get anything stripped.
indentation of IF stuff is ignored as is newline on end.it did two indents in STv3. result now is
- <multi-char> not allowed. do <\r><\n> instead. no <\r>. <\n> does locale specific output
- groups have no name other than dir name or group file name
- \n stripped if no output on a line and literal or <...> including IF
EMPHATICALLY SAME:
- null elements get ignored. null list elements do not get counted for <i> and <i0> indexes.
- trim whitespace at start/end of templates; just too hard to get rid of whitespace later.
thread safety
assume thread safe modifying access to templates, adaptors, attributes, imports, and renderer access on STGroup/ST (they are synchronized).
18 Comments
Hide/Show CommentsJan 28, 2011
Victor Bartel
Greetings,
You spoke a lot about productivity for programmers. StringTemplate is some kind of evolution in the world of java template engines. But one of important shortcoming of StringTemplate v3 (especially for web development) is errors reporting. One mile stacktrace instead of exact error message (line, col expression, etc) can not speed up development process. StringTemplate v3 has a system of error listers but this system is very limited. To illuminate this problem you can see which error reporting systems have RoR (default TE), Play! (default TE), scalate. Will you review error reporting in v4 of StringTemplate ?
Jan 29, 2011
Terence Parr
It is much improved and i also provide STViz debugger
Feb 01, 2011
Victor Bartel
Nice, I hope that it will be very useful. An another question (for web developers), what about the inheritance in templates and not in initialization java/c# code ? ST is widely used by a lot of frameworks like spring mvc, .net mvc, but it is not so productive to specify inheritance rules from the code each time when we use ST (in controller action for example). Template inheritance is very important for mvc framework, are you agree to this?
Mar 10, 2011
Terence Parr
Yes, using the import statement, you can refer to templates in a different group. So in group file wacky, you can import a base group and reference its templates.
in this case, we can assume that template x is inherited from base.stg.
Dec 08, 2011
Cristian Malinescu
I used ST both the Java and C# versions for long time for the purpose of rendering dynamic content and code generation and I was in love with it's draconian enforcement of separation
for the MVC domain, however, since the major changes introduced with the version 4 I find very unsuited to use ST for HTML templating - having to embrace the html content between constructs
of this form plus the necessity to declare the variable placeholders so - key names duplication and using language specific API - constructors, to declare the delimiters etc.
makes the new ST 4 a no-no for me. I'm looking to switch back to FreeMarker or to the new guy in town MVEL. Thanks Terence for helping me make good business for many years with
your work, I may have missed some tricks which would have allowed to use ST4 in the same non-invasive way as the previous versions but I couldn't find them.
index(browser) ::= <<
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html>
<head>
</head>
<body>
<p>Hi browser $browser$ ...</p>
</body>
</html>
>>
Dec 09, 2011
Terence Parr
Hi Christian, i'm going to add an STGroupDir that doesn't require the headers in the .st files. is that your only complaint?
Ter
Dec 19, 2011
Doug
+1 for the previous comment. I've just downloaded the most recent version and the tutorials that universally say you can just have .st file with content and no explicit template prototype (or whatever it is) are all wrong; this makes the syntax for full files annoying. I'm going else where for a simpler solution, but I thought I'd post my -1 to the -> v4 changes here too. :/
Jan 18, 2012
Terence Parr
Grab latest from depot; i added STRawGroupDir for this purpose.
Jan 23, 2012
Alexander Ryzhov
I am having trouble migrating from ST3 to ST4. With ST3 I was able to have global attributes that are accessible in all templates. With ST4 I don't see a way to do it. I want to have attribute <xyz> that is accessible in template B if B is called from A like this: <B()>. My template structure is quite complex and it's unreasonable for me to pass all global attributes in all calls.
Jan 23, 2012
Terence Parr
Do you mean <B()> or <B>? If you define attributes in A and then include B in A, B will be able to see those attributes.
Jan 23, 2012
Alexander Ryzhov
Here is my situation: template A is defined in a group. It contains a call to B() from an imported group, like this: "... <B()> ... ". Template B contains the attribute: " ... <xyz> ... ". I render A by calling:
I tried adding attribute xyz to A before calling render(), like this:
but I get an exception:
I appreciate your help!
Jan 24, 2012
Terence Parr
Sounds like we need to take this to the interest list. You must define xyz in A:
A(xyz) ::= "<B()>"
I assume you are not doing that.
Jan 24, 2012
Alexander Ryzhov
I did that and it helped. Thanks!
Feb 26, 2012
Richard Grin
I would like to refresh a template/templateGroup but I can't find a refresh method (there was a setRefreshInterval in StringTemplateGroup). In version 4, what is the politics for caching and how can I refresh a template?
Feb 26, 2012
Terence Parr
call unload() at your own interval.
Feb 29, 2012
Richard Grin
Thanks for your answer.
A very simple question: how can I adapt this method for version 4 ? I know that I have to replace toString() by render() but how to write the 2 previous lines (without writing an explicit loop for the attributes in the map)?
To sum up,
It was very useful for me in the version 2 of StringTemplate.
May 22, 2012
DNA 2010
I've figured it out. Basically for all: when you are switching from 2.7.7 to 4 and you had some include commands in your template, like this one:
File: c:\template\test\index.st
<div>
$test/otherSTFile()$
</div>
then the root path for your includes were always the path specified by the STGroup (e.g. in the case above c:\templates\). In version 4 the root path is simple the path of the current template. In my example this would be c:\template\test. So I had to change the code above to
<div>
$otherSTFile()$
</div>
and everything worked fine again. Thanks Terence for the fast reply and keep up the good work.
May 21, 2012
Terence Parr
Sorry, but I'm not sure I understand the details of the problem. perhaps you should mail this to the stringtemplate-list.