Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use FreeMarker to template nested Pojos?

I'm investigating using FreeMarker to write EDI files. These are basically heavily formatted (and validated) electronic invoices. I decided to get started by writing a simple example and am stuck getting it to template a 'nested pojo'. By this I mean a POJO which contains POJOs where both of these have data I want in my output. I wrote a unit test (self contained) that is failing for an unknown reason. When I run the test I get the following exception:

Expression user.getSub is undefined on line 1, column 24 in simple.
The problematic instruction:
----------
==> ${user.getSub().user} [on line 1, column 22 in simple]
----------

Java backtrace for programmers:
----------
freemarker.core.InvalidReferenceException: Expression user.getSub is undefined on line 1, column 24 in simple.
    at freemarker.core.TemplateObject.assertNonNull(TemplateObject.java:124)
    at freemarker.core.TemplateObject.invalidTypeException(TemplateObject.java:134)
    <snip>
    example.TestFreeMarkerTemplating.testSimpleTemplate(TestFreeMarkerTemplating.java:23)
    <snip>

I've tried many variations on the template, and haven't met success. This is the test:

package example;

import java.io.*;
import org.junit.Test;
import freemarker.cache.StringTemplateLoader;
import freemarker.ext.beans.BeansWrapper;
import freemarker.template.*;

import static org.junit.Assert.*;

public class TestFreeMarkerTemplating {

Configuration cfg = new Configuration();
StringTemplateLoader stringLoader = new StringTemplateLoader();
{ cfg.setTemplateLoader(stringLoader);
cfg.setObjectWrapper(new BeansWrapper()); }

@Test
public void testSimpleTemplate() throws TemplateException, IOException{
    stringLoader.putTemplate("simple", "Welcome ${user}. Sub ${user.getSub().user}");
    Template temp = cfg.getTemplate("simple");
    StringWriter out = new StringWriter();
    temp.process(new TestPojo(), out);

    assertEquals("Welcome Andy. Sub Bill", out.toString());
}

public static class TestPojo {
    private final String user = "Andy";
    private final SubPojo sub = new SubPojo();

    public String getUser() { return user; }
    public SubPojo getSub() { return sub; }
}

public static class SubPojo {
    private final String user = "Bill";

    public String getUser() { return user; }
}

 }

Thanks for any help!

like image 342
Spina Avatar asked May 29 '12 22:05

Spina


People also ask

What is the use of FreeMarker template?

Apache FreeMarker is a free Java-based template engine, originally focusing on dynamic web page generation with MVC software architecture. However, it is a general purpose template engine, with no dependency on servlets or HTTP or HTML, and is thus often used for generating source code, configuration files or e-mails.

What is FreeMarker template language?

FreeMarker is a template engine, written in Java, and maintained by the Apache Foundation.

How do you handle null values in FreeMarker template?

The most common method of detecting for empty or null values uses the has_content function and the trim function. The has_content function is often used with another built-in FreeMarker function to detect for null values. Check the FreeMarker documentation for more information on the has_content function.


1 Answers

You have set the TestPojo instance itself as the data-model root, so the user in user.getSub() is the String "Andy", which doesn't have a getSub method. The correct template is "Welcome ${user}. Sub ${getSub().user}". But it's nicer to write as "Welcome ${user}. Sub ${sub.user}".

like image 67
ddekany Avatar answered Sep 29 '22 23:09

ddekany