Passing a List of Objects to Freemarker and then Looping

Mark Nenadov picture Mark Nenadov · May 12, 2011 · Viewed 64.1k times · Source

I've been acquainting myself with FreeMarker, a template engine for Java.

I got to the point where I am able to pass an object to the template engine through a Hash Map. That works alright. But as soon as I try to pass any sort of set of multiple objects to FreeMarker it gives me a freemarker.template.TemplateException and complains that it "Expected collection or sequence. jobs evaluated instead to freemarker.template.SimpleHash".

From what I understand from reading up on this in the various resources, this is to be expected.

Now, I have done much of the leg work and found a number of people commenting on how to get around this. But, quite frankly, (a) for many of the examples it was unclear as to how exactly their advice applies in my case--even though I've known Java basics for quite a while I'm pretty new to some of the architecture pertaining to Java web apps and (b) I'm confused as to which of the approaches was the best approach.

All I want to do, at the most simplified level, is basically this:

  1. I have a simple Servlet.

  2. I have a simple class (for this example named Invoice) with a few methods and properties.

  3. I want to have my servlet (in some fashion) present a list/array/sequence/hashmap of instances of these objects (or views of those objects) via FreeMarker's process method.

  4. I want to have my .ftl template do a loop through the list/array/sequence/hashmap and display method results, something like this:

< # list invoices as invoice> 
Invoice note: ${invoice.getNote()}, Invoice Amount:${invoice.getAmount()} 
< / # list>

Now, I'm not necessarily looking for the quick & dirty solution to this. I'm new to FreeMarker, but I want to do this in the proper way that is elegant and good design. So I'm open to completely rethinking this approach. Can someone help me see what I need to do to get something like this to work?

Answer

st.never picture st.never · May 12, 2011

Is "jobs" really a collection? Please post a snippet of code where you are creating and processing your template.

I just wrote a quick test to check:

public void testFreeMarker() throws Exception {

    List<Invoice> invoices = Arrays.asList(
       new Invoice( "note1", "amount1" ), 
       new Invoice( "note2", "amount2" ) );
    Map<String, Object> root = new HashMap<String, Object>();
    root.put( "invoices", invoices );
    StringWriter out = new StringWriter();

    Configuration cfg = new Configuration();
    cfg.setClassForTemplateLoading( FreemarkerUtils.class, "/templates" );
    cfg.setObjectWrapper( new DefaultObjectWrapper() );
    Template temp = cfg.getTemplate( "listTest.ftl" );
    temp.process( root, out );

    System.out.println( out.getBuffer().toString() );
}

The template is just:

<#list invoices as invoice>
 Item: ${invoice.note} - ${invoice.amount}
</#list>

The result is as expected:

Item: note1 - amount1
Item: note2 - amount2