Sunday, 5 July 2020

FreeMarker: Define custom directive by implementing TemplateDirectiveModel interface

In this post, I am going to explain how to define custom directive by implementing TemplateDirectiveModel interface.

 

Step 1: Create ‘LowerCaseFilterWriter’ that extends the Writer class and converts the char. Array to lowercase.

 

LowerCaseFilterWriter.java
package com.sample.app.writers;

import java.io.IOException;
import java.io.Writer;

public class LowerCaseFilterWriter extends Writer {

	private final Writer out;

	public LowerCaseFilterWriter(Writer out) {
		this.out = out;
	}

	public void write(char[] cbuf, int off, int len) throws IOException {
		char[] transformedCbuf = new char[len];
		for (int i = 0; i < len; i++) {
			transformedCbuf[i] = Character.toLowerCase(cbuf[i + off]);
		}
		out.write(transformedCbuf);
	}

	public void flush() throws IOException {
		out.flush();
	}

	public void close() throws IOException {
		out.close();
	}

} 

Step 2: Create ‘StringLowercaseDirective’ by implementing TemplateDirectiveModel interface.

 

StringLowercaseDirective.java

package com.sample.app;

import java.io.IOException;
import java.util.Map;

import com.sample.app.writers.LowerCaseFilterWriter;

import freemarker.core.Environment;
import freemarker.template.TemplateDirectiveBody;
import freemarker.template.TemplateDirectiveModel;
import freemarker.template.TemplateException;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;

public class StringLowercaseDirective implements TemplateDirectiveModel {

	@Override
	public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)
			throws TemplateException, IOException {
		if (!params.isEmpty()) {
			throw new TemplateModelException("This directive doesn't allow parameters.");
		}
		if (loopVars.length != 0) {
			throw new TemplateModelException("This directive doesn't allow loop variables.");
		}

		if (body == null) {
			throw new RuntimeException("Please provide body");
		}

		body.render(new LowerCaseFilterWriter(env.getOut()));

	}

}

Step 3: Make the directive available to the template.

 

We can do this by adding the instance of the directive to root model object.

 

StringLowercaseDirective directive = new StringLowercaseDirective();

                 

Map<String, Object> modelObject = new HashMap<String, Object>();

modelObject.put("lower", directive);


Create a file ‘stringLowercase.ftl’ in src/main/resources/templates folder.

 

stringLowercase.ftl
HELLO, HOW ARE YOU
<@lower>
  bar
  <#-- All kind of FTL is allowed here -->
  <#list ["RED", "GREEN", "BLUE", "YELLOW", "WHITE"] as color>
    ${color}
  </#list>
  I WILL BE CONVERTED TO LOWER CASE.
</@lower>

Define StringLowercaseDirectivePopulator.

 

StringLowercaseDirectivePopulator.java

package com.sample.app;

import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;

import com.sample.app.util.FreeMarkerUtil;

public class StringLowercaseDirectivePopulator {
	public static void main(String args[]) throws Exception {
		StringLowercaseDirective directive = new StringLowercaseDirective();
		
		Map<String, Object> modelObject = new HashMap<String, Object>();
		modelObject.put("lower", directive);

		StringWriter stringWriter = FreeMarkerUtil.mergeModelAndTemplate(modelObject, "stringLowercase.ftl");
		System.out.println(stringWriter.toString().trim());

	}
}

Run the application, you will see below messages in the console.

HELLO, HOW ARE YOU
  bar
    red
    green
    blue
    yellow
    white
  i will be converted to lower case.

Previous                                                    Next                                                    Home

No comments:

Post a Comment