Skip to content

An alternate template engine which is able to handle template strings larger than 64k

License

Notifications You must be signed in to change notification settings

mbjarland/groovy-streaming-template-engine

Repository files navigation

Streaming Template Engine for Groovy

News

  • 2014.Aug.13 - A pull request which contains the StreamingTemplateEngine has been submitted to the groovy-core project at pull request 503. This means that there is a chance that the class might make it into the groovy language some time soon.
  • 2014.Aug.13 - Updating dependency versions to gradle 1.9 and groovy 2.3.6. Also updated the project version to 2.3.6.1 to reflect the fact that it is now compiled against groovy 2.3.6. Version 2.3.6.1 is published to the maven repository referenced to in the sample_usage.groovy file and in the example further down on this page.
  • 2014.Aug.13 - Removing erroneous references to GPL in build.gradle, making it more obvious that the project is licensed under the Apache license, adding license reference to this readme, and fixing typos. Thank you to Etienne Studer for pointing out the deficiencies.
  • 2014.Feb.15 - Two issues (issue #1 and issue #2) with this template engine are now closed thanks to a contribution by Wilfried Middleton. Many thanks for the infinite debug sessions and deep thinking!
  • 2014.Feb.15 - For those interested in downloading this artifact via our maven repository - we now use a groovy-version-bound versioning scheme for the template engine. So for groovy version '2.1.9' the current template engine version is '2.1.9.1'. We will increment the last number as needed. Currently we have only deployed versions '2.1.9.1' (groovy 2.1.9) and '2.2.1.1' (groovy 2.2.1).

What is this?

This repository contains a templating engine for the groovy programming language. It is an alternative and drop in replacement for the existing SimpleTemplateEngine and GStringTemplateEngine engines included in the groovy libraries.

The name is slightly misleading as the code is not exactly based on streaming, but the term 'streaming' captures the essense of the idea and was the best I could come up with at the time. The engine was initially called SmartTemplateEngine but somebody once told me that calling your baby smart is obnoxious so I renamed it.

Why another groovy template engine?

The existing groovy template engines SimpleTemplateEngine and GStringTemplateEngine can not handle template strings larger than 64k (unit tests proving that fact). They throw the following exceptions when asked to template a string of 64k+1 character:

GStringTemplateEngine

 groovy.lang.GroovyRuntimeException: Failed to parse template script (your template may contain an error or be trying to use expressions not currently supported): startup failed:
GStringTemplateScript1.groovy: 2: String too long. The given string is 65536 Unicode code units long, but only a maximum of 65535 is allowed.
 @ line 2, column 79.
   new Binding(delegate); out << """...
                                                     ^

SimpleTemplateEngine

groovy.lang.GroovyRuntimeException: Failed to parse template script (your template may contain an error or be trying to use expressions not currently supported): startup failed:
SimpleTemplateScript1.groovy: 1: String too long. The given string is 65536 Unicode code units long, but only a maximum of 65535 is allowed.
 @ line 1, column 11.
   out.print("""...
                  ^

in my experience, templates larger than 64k are not all that uncommon (I certainly run into them all the time) and this limitation seems artificial and unnecessary.

Usage

The interface for this template engine is identical to the existing groovy template engines.

Example code (tested with groovy 2.3.6 or below):

@GrabResolver(name='groovy-template', root='http://artifacts.iteego.com/artifactory/public-release-local')
@Grab('org.codehaus.groovy:groovy-streaming-template-engine:2.3.6.1')
@Grab('org.codehaus.groovy:groovy-templates:2.3.6')

import groovy.text.StreamingTemplateEngine
import groovy.text.SimpleTemplateEngine
import groovy.text.Template

StreamingTemplateEngine engine = new StreamingTemplateEngine()

def binding = [bird: 'raven', subject: 'writing desk',  flag: true]
String data = '''Alice, why is a ${bird} <%= flag ? 'like' : 'not like' %> a <%= subject %><% out << '?' %>'''

Template template = engine.createTemplate(data)
Writable writable = template.make(binding)
StringWriter sw = new StringWriter()
writable.writeTo(sw)

println "RESULT: $sw"

//now test with a data set that breaks the existing template engines
StringBuilder b = new StringBuilder()
def sixtyFourAs = "a" * 64
1024.times { b << sixtyFourAs }
def sixtyFourKAs = b.toString()

println "LENGTH: ${sixtyFourKAs.length()}"

engine.createTemplate(sixtyFourKAs).make()

boolean threwException = false
try { 
  new SimpleTemplateEngine().createTemplate(sixtyFourKAs).make()
} catch (GroovyRuntimeException e) {  
  println "Simple template engine fails..."
  threwException = e.message.contains('String too long')
}
assert threwException

executing this gives:

$ groovy sample_usage.groovy 
RESULT: Alice, why is a raven like a writing desk?
LENGTH: 65536
Simple template engine fails...

(this code can be found in the samlpe_usage.groovy file in the root of the repo)

Normally, the template data would probably be pulled from a file (ala jsp, gsp, asp, xsp) but the above demonstrates using the template engine on a string, is self contained, and gives a feel for what this repo is about.

Limitations

The engine in this repo can handle templates into the hundreds of megabytes.

This does however not mean the engine is fool proof. There are still limitations inherited from the bytecode file format on the jvm...and any potential bugs caused by mental stumbling on my part.

As an example of such a limitation, creating a 300M template string with a template expression (i.e. '${bird}') every one kilobyte breaks the code with a "method too large" exception from the jvm.

Alternatives

Morten Kjetland has implemented a replacement groovy template engine for the play framework. This looks very promising. For details, check out his blog post about the release.

I have not performed any tests on play framework engine and I dont' know if it has size limitations similar to the built in groovy ones or how it compares to the one in this repo. However, considering the complexity of Mortens implementation and the competence of the author I would make a qualified guess that it is very capable.

The play framework engine uses a template language slightly different from the templage language used in the built in groovy template engines and the engine in this git repo.

Why is this not part of the groovy libraries?

Perhaps one day it might be. I am certainly open to it if there is interest from the groovy maintainers. I think either fixing the existing engines or adding a new one which can handle arbitrary template sizes is essential for a modern, dynamic language such as groovy.

History

I initially wrote this template engine a number of years ago, but omitted to make it publicly available as I assumed that such a glaring limitation would be addressed by the groovy community and/or creators soon enough to make sharing the repository pointless. Years passed and about once a year I went back to my repo, ran my negative unit tests (which prove that the current groovy version still breaks for strings > 64k), shook my head and went back to my day job.

As templates can be used for a large number of arbitrary programming tasks ranging from code generation, rendering of various text based formats, rendering HTML etc etc and as a number of years have passed with no fix the 64k limitation in sight, I figured this code might save somebody some time.

Could also be there is another template engine out there and I just failed to find it...if so, please shoot me an email and I will adjust accordingly.

License

Streaming Template Engine for Groovy is licensed under the terms of the Apache License, Version 2.0.

Disclaimer

This repo does contain a fairly thought through set of unit tests and I believe the engine does what it is supposed to do (at least to a degree comparable to the existing template engines).

That being said, this code has not been tested in production and no guarantees are made as for the validity of the code or the robustness of the templating logic.

About the Author

name: Matias Bjarland - coordinates: Gothenburg, Sweden

I run a software consultancy firm (http://iteego.com) which specializes in large scale e-commerce implementations and enterprise software integrations.

I spend some of my spare cycles with groovy, gradle, grails, lisp, reading philosophy, learning new languages, rock climbing, marveling over the beauty of the universe, and barefoot running.

Feel free to ping me via email at [email protected].

About

An alternate template engine which is able to handle template strings larger than 64k

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published