Freemarker, in fact, has very good documentation. It's easy to start using it without any specific knowledge. In this post I would like to share a few issues which I found very useful. Let's start with very basic e-mail message template.
In this template we assume that some object (bean) user with public properties firstName and lastName must be passed to template engine in order to build e-mail message. Let's save this template to message.ftl file (.ftl is default file extension for Freemarker templates). To process this template we need few simple steps:Hello ${user.fistName} ${user.lastName}!
Welcome to the world of templates!
It's quite clear what the code does: create configuration, create context (simple map) and then process template (stored in file). When this code snippet finishes, writer will contain fully processed template. The tricky part here is such code:Configuration cfg = new Configuration();
// Specify the data source where the template files come from.
cfg.setDirectoryForTemplateLoading( new File("/where/you/store/templates"));
// Specify how templates will see the data-model
cfg.setObjectWrapper( ObjectWrapper.DEFAULT_WRAPPER );
final Map< String, Object > context = new HashMap< String, Object >();
final User user = new User( "First Name", "Last Name" );
context.put( "user", user );
final Template t = cfg.getTemplate( "message.ftl");
final Environment env = t.createProcessingEnvironment( context, writer );
env.process();
We will see what it means later but for know it's enough to say that it has influence on how Freemarker processes objects passed to template (via context).// Specify how templates will see the data-model
cfg.setObjectWrapper( ObjectWrapper.DEFAULT_WRAPPER );
We are done with e-mail message but what if you need to construct e-mail subject in template as well and return it back to callee? Freemarker allows to do that using environment. Let's modify the template a little bit:
So in this template we create internal variable subject which we will use later in code. We need just a few additional steps:<#assign subject="Congratulations ${user.fistName} ${user.lastName}!" />
Hello ${user.fistName} ${user.lastName}!
Welcome to the world of templates!
Next interesting question is about object properties / functions / static functions which you could use inside template. Basically, with ObjectWrapper.DEFAULT_WRAPPER you are free to use any object property which comply with Java Beans specification. In case you need, for example, calls like getClass(), you need ObjectWrapper.BEANS_WRAPPER....
env.process();
String subject = "";
final TemplateModel subjectModel = env.getVariable( "subject" );
if( subjectModel instanceof TemplateScalarModel ) {
subject = ( ( TemplateScalarModel )subjectModel ).getAsString();
}
Using static functions / properties could be done by means of static models. Let say you have a class with static my.package.StaticUtil. To use static members of this class inside the template we need to use code like:cfg.setObjectWrapper( ObjectWrapper.BEANS_WRAPPER );
Later in template you can use constructions like ${StaticUtil.someStaticFunction()} to access static members.final BeansWrapper wrapper = BeansWrapper.getDefaultInstance();
final TemplateHashModel staticModels = wrapper.getStaticModels();
final TemplateHashModel staticUtil =( TemplateHashModel )staticModels
.get( "my.package.StaticUtil" );
context.put( "StaticUtil", staticUtil );
That's it for now. One thing is worthwhile to say is that Freemarker has good integration with Eclipse via JBoss Tools.