Freemarker iterating over hashmap keys

Solution 1:

Edit: Don't use this solution with FreeMarker 2.3.25 and up, especially not .get(prop). See other answers.

You use the built-in keys function, e.g. this should work:

<#list user?keys as prop>
    ${prop} = ${user.get(prop)}
</#list>  

Solution 2:

FYI, it looks like the syntax for retrieving the values has changed according to:

http://freemarker.sourceforge.net/docs/ref_builtins_hash.html

<#assign h = {"name":"mouse", "price":50}>
<#assign keys = h?keys>
<#list keys as key>${key} = ${h[key]}; </#list>

Solution 3:

Since 2.3.25, do it like this:

<#list user as propName, propValue>
  ${propName} = ${propValue}
</#list>

Note that this also works with non-string keys (unlike map[key], which had to be written as map?api.get(key) then).

Before 2.3.25 the standard solution was:

<#list user?keys as prop>
  ${prop} = ${user[prop]}
</#list>

However, some really old FreeMarker integrations use a strange configuration, where the public Map methods (like getClass) appear as keys. That happens as they are using a pure BeansWrapper (instead of DefaultObjectWrapper) whose simpleMapWrapper property was left on false. You should avoid such a setup, as it mixes the methods with real Map entries. But if you run into such unfortunate setup, the way to escape the situation is using the exposed Java methods, such as user.entrySet(), user.get(key), etc., and not using the template language constructs like ?keys or user[key].

Solution 4:

If using a BeansWrapper with an exposure level of Expose.SAFE or Expose.ALL, then the standard Java approach of iterating the entry set can be employed:

For example, the following will work in Freemarker (since at least version 2.3.19):

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

In Struts2, for instance, an extension of the BeanWrapper is used with the exposure level defaulted to allow this manner of iteration.

Solution 5:

Iterating Objects

If your map keys is an object and not an string, you can iterate it using Freemarker.

1) Convert the map into a list in the controller:

List<Map.Entry<myObjectKey, myObjectValue>> convertedMap  = new ArrayList(originalMap.entrySet());

2) Iterate the map in the Freemarker template, accessing to the object in the Key and the Object in the Value:

<#list convertedMap as item>
    <#assign myObjectKey = item.getKey()/>
    <#assign myObjectValue = item.getValue()/>
    [...]
</#list>