Index

Table of contents

Freemarker

Hello World

public static void main(String[] args) throws IOException, TemplateException {
        Configuration cfg = new Configuration(Configuration.VERSION_2_3_23);

        StringTemplateLoader tl = new StringTemplateLoader();
        tl.putTemplate("bla", "blabla ${test} blabla");
        cfg.setTemplateLoader(tl);
        Template template = cfg.getTemplate("bla");

        // Build the data-model
        Map<String, Object> data = new HashMap<String, Object>();
        data.put("test", "Hello World!");

        // Console output
        Writer out = new OutputStreamWriter(System.out);
        template.process(data, out);
        out.flush();
}
loading templates from the classpath
TemplateLoader ctl = new ClassTemplateLoader(getClass(), "/freemarker");
cfg.setTemplateLoader(ctl);
cfg.getTemplate("filename.tpl")
loading templates from the filesystem
TemplateLoader ftl = new FileTemplateLoader(new File(templatePath));
chaining multiple template loaders
TemplateLoader mtl = new MultiTemplateLoader(new TemplateLoader[] { ftl, ctl });
storing the result in a String
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Writer writer = new OutputStreamWriter(baos);
cfg.getTemplate(template).process(data, writer);
writer.flush();
return baos.toString("UTF-8");

escaping output

comments
<#-- programmer's grief -->
filename extension for auto escape html special chars
.ftlh
filename extension for auto escape xml special chars
.ftlx
force escaping for a specific output format regardless of filename (inludes not affected)
<#ftl output_format="HTML">
print raw value (no escaping)
${[value]?no_esc}
documentation
https://freemarker.apache.org/docs/dgui_quickstart_template.html#dgui_quickstart_template_autoescaping
https://freemarker.apache.org/docs/pgui_config_outputformatsautoesc.html
https://freemarker.apache.org/docs/dgui_misc_autoescaping.html

whitespace

trim lines
<#compress>
...
<#/compress>
documentation
https://freemarker.apache.org/docs/dgui_misc_whitespace.html

basics

assign variable
<#assign x = 1>
different kind of null checks
?? -> not null
?has_content -> not empty
![fallback] -> fallback if null
(user.price)!    handles all missing variable errors thrown during the evaluation of the ()
(user.price)!0   default value if any part of path is null
optional value
${(log)!}
${variable.method()!}
default value if null
${[variable]![preset]}
section depending on optional value
<#if log??>
    ${log}
</#if>

types

string

string comparison
<#if someString == someOtherString>
<#if someString != someOtherString>

number

defining and incrementing
<#assign x=0>
<#assign x=x+1>
<#assign x+=1>
string to number
${'999'?number}
compare 2 numbers
${[number] == [number]}
${[number] lt [number]}
${[number] gt [number]}
${[number] lte [number]}
${[number] gte [number]}
print variable without readability characters (numbers without commas, etc)
${question.id?c}

boolean

logical or
||
logical and
&&
logical not
!

map

create a simple map
{'[key]': '[value]'}
read a value from a map
${map[key]}
iterate keys
<#list map?keys as key>${key} = ${map[key]}</#list>

sequence

defining a sequence
<#assign values = ["a", "b"]>
<#list seq[1..3] as i>${i}</#list>
accessing a value from a sequence
${values[0]}
getting the size of a sequence
${values?size}
collection is empty?
?has_content
?size = 0
collection contains value?
?seq_contains([value])

date

date with format
${aDateTime?string["dd.MM.yyyy, HH:mm"]}
${aDateTime?iso("Europe/Rome")}

fragments

include another template
<#include "layout/bottom.tpl"/>
simple macro
<#macro header title>
	<h1>${title}</h1>
</#macro>
macro usage
<@header title='blabla' />
macro with optional value
<#macro [name] [param]="[preset]" >
macro with optional value and check
<#macro [name] [param]="" >
	<#if ([param]?has_content)>
macro with nested content
<#macro wrap>
	before <#nested> after
</#macro>
calling a macro with nested content
<@wrap>
	<b>inbetween</b>
</@wrap>

control flow

ternary operator
${result.incorrect ? then ('incorrect', 'visible')}
${(variable.property == 0) ? then ('a', 'b')}
if else
<#if condition>
  ...
<#elseif condition>
  ...
<#else>
  ...
</#if>
iterating a sequence
<#list values as value>
	<h1>${value}</h1>
</#list>
for each loop
<#list someList as entry>
	${entry.someProperty}
</#list>
iterating with index
<#list 0..variable?size-1 as index>
	<p>${variable[index]}</p>
</#list>

Tree structures

navigating a tree structure
<#macro tree nodes>
  <#list nodes.getChildren() as node>
    <ul>
      <li>
        ${node.getName()}
        <#if node.hasChildren()>
          <@tree nodes=node />
        </#if>
      </li>
    </ul>
  </#list>
</#macro>
to call
<@tree nodes=root/>
sample tree node
public class TreeNode {
	private List<TreeNode> children = new ArrayList<>();
	private String name;

	public TreeNode(String name) {
		this.name = name;
	}

	public List<TreeNode> getChildren() {
		return children;
	}

	public String getName() {
		return name;
	}

	public boolean hasChildren() {
		return !children.isEmpty();
	}
}

Links

try freemarker code online
https://try.freemarker.apache.org/