dev2707
dev2707

Reputation: 41

How to retrive a List objects from HashMap and iterate in free marker template?

I have a Java Hashmap object which stores a key value pair in form of org.w3c.dom.Element: java.util.ArrayList. after populating the HashMap, I put it in Freemarker context along with List of org.w3c.dom.Element.

When I try to get the List object using below code snippet

<#list ElementList as key>
<#assign fh =ElemmentListMap>
  ${fh[key]}
</#list>

It says ${fh[key]} is undefined. Please let me how to get the solution for it or feel free to give another solution.

Upvotes: 4

Views: 3727

Answers (2)

ddekany
ddekany

Reputation: 31162

Update: Starting from 2.3.22, you should just use ?api to work this around. See this answer, or this FAQ entry for details.

The old answer:

The root of the problem here is that the FreeMarker Template Language doesn't have an equivalent of the Map type of Java. Instead it has a type called "hash", which is similar to a Map, but it only supports string keys (variable names, originally). So when it sees fh[key], it will assume that key has a string value (in this case that will be the result of key.toString() due to how POJO-s are wrapped), and hence will not find the item. So the solution would be not using the [] operator for non-string keys, but the Java API, Map.get(Object key).

And the rest is outdated...

But you will run into yet another obstacle if you try to do that: the default ObjectWrapper doesn't expose the methods of Map-s since the string keys of the Map already populate the same name-space. I hate the default ObjectWrapper for various other reasons too, so I always set up FreeMarker like this:

BeansWrapper wrapper = new BeansWrapper();
wrapper.setSimpleMapWrapper(true);
cfg.setObjectWrapper(wrapper);

With this wrapper you can use Map-s both as myMap[someStringKey] or as myMap(whateverKey). So in your case it would be ${fh(key)}. Again, this doesn't work with the default ObjectWrapper.

To make things worse, I see you are using W3C DOM here. The above wrapper doesn't wrap Node-s automatically in a way so that you could use the FreeMarker XML features. So if you need that, then unless you always wrap DOM node manually, you will have to extend BeansWrapper to recognize DOM Node-s. That's simple to do luckily:

public class MyObjectWrapper extends freemarker.ext.beans.BeansWrapper {

    public TemplateModel wrap(Object obj) throws TemplateModelException {
        if (obj instanceof org.w3c.dom.Node) {
           return freemarker.ext.dom.NodeModel.wrap((org.w3c.dom.Node) obj);
        } else {
           return super.wrap(obj);
        }
    }

}

The last thing to consider if the environment you are using FreeMarker in already has a custom ObjectWrapper. In that case, you better try to extend that somehow...

Upvotes: 4

dns
dns

Reputation: 2815

Your java code should be:

Map map = new HashMap();
List list = new ArrayList();
list.add("red");
list.add("green");
list.add("blue");
map.put("array_list", list);

And the freemarker template should be:

<#list array_list as i>
    ${i}
</#list>

Output:

red
green
blue 

Upvotes: 0

Related Questions