Thursday, January 13, 2011

Iterate over JAVA HashMap in FreeMarker

Java HashMap can be iterated in FreeMarker by using a <#list> tag as follows:

<#list hashMap?keys as key>
        ${key}=${hashMap[key]}
<#list>


If you are using the above code with default FreeMarker Configuration then there would be some different behavior during iteration. For example if the HashMap is:

HashMap hashMap = new HashMap();
hashMap.put("1","one");
hashMap.put("2","two"); 

By iterating on hashMap with default Configuration it will output following keys in result:

put
remove
entrySet
hashCode
productElement
clear
isEmpty
1
values
empty
underlying
productElements
copy
getClass
get
copy$default$1
equals
productPrefix
class
canEqual
keySet
size
2
containsKey
productArity
containsValue
productIterator
toString
putAll        


This result shows that the iteration is done on all the available hashMap properties.

To get rid of this you have to set the FreeMarker Configuration as follows:


Configuration configuration = new Configuration();
BeansWrapper wrapper = (BeansWrapper) this.configuration.getObjectWrapper();
wrapper.setSimpleMapWrapper(true);
this.configuration.setObjectWrapper(wrapper);

Here the BeanWrapper's simpleMapWrapper property is set as 'true'. After setting this configuration the results over iterating on hashMap will give only the defined key-value pair.

rizzz86

6 comments:

Javin @ Tibco RV Tutorial said...

Hi,
Thanks for htis Nice artilce just to add while discussing about HashMap its worth mentioning following questions which frequently asked in Java interviews now days like How HashMap works in Java or How get() method of HashMap works in JAVA very often. on concept point of view these questions are great and expose the candidate if doesn't know deep details.

Javin
FIX Protocol tutorial

Rizwan Ahmed said...

@ Javin @ Tibco RV Tutorial

Thanks for the suggestion.

Anonymous said...

Hi Rizwan, I am new to FreeMarker and would like to check with you on this:

My hashmap is not simple like a primitive string. Instead of Map, my model is a Map where Person is a class object.

My code is something like this:

BeansWrapper wrapper = BeansWrapper.getDefaultInstance();
TemplateModel mapModel = wrapper.wrap(hashMap);

In the template:
<#list hashMap?keys as key>
${key}=${hashMap.get(key)}
<#list>

I will also get the same result as listed.

However, if I put in wrapper.setSimpleMapWrapper(true),
I will not be able to get any value from the hashMap.get(key)...

Any advice?

Rizwan Ahmed said...

Anonymous,

Before setting wrapper.setSimpleMapWrapper(true) property check following:

Do you get your (Person) values with the other values that I have mentioned.

You can see that I am getting "1" and "2" with other values as well before setting property to true.

rizzz86

Rizwan Ahmed said...
This comment has been removed by the author.
Anonymous said...

Actually, in Java the performance is better if you iterate over the entry set instead of the key set. For example, the following will work in Freemarker:

<#list map.entrySet() as entry>
<input type="hidden" name="${entry.key}" value="${entry.value}" />
</#list>