Freemarker iterating over hashmap keys

JavaFreemarker

Java Problem Overview


Freemarker has two collection datatypes, lists and hashmaps Is there a way to iterate over hashmap keys just as we do with lists?

So if I have a var with data lets say:

user : {
  name : "user"
  email : "[email protected]"
  homepage : "http://nosuchpage.org"
}

I would like to print all the user's properties with their value. This is invalid, but the goal is clear:

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

Java Solutions


Solution 1 - Java

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 - Java

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 - Java

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 - Java

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 - Java

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> 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()/> [...]

Solution 6 - Java

For completeness, it's worth mentioning there's a decent handling of empty collections in Freemarker since recently.

So the most convenient way to iterate a map is:

<#list tags>
<ul class="posts">
    <#items as tagName, tagCount>
        <li>{$tagName} (${tagCount})</li>
    </#items>
</ul>
<#else>
    <p>No tags found.</p>
</#list>

No more <#if ...> wrappers.

Solution 7 - Java

You can use a single quote to access the key that you set in your Java program.

If you set a Map in Java like this

Map<String,Object> hash = new HashMap<String,Object>();
hash.put("firstname", "a");
hash.put("lastname", "b");

Map<String,Object> map = new HashMap<String,Object>();
map.put("hash", hash);

Then you can access the members of 'hash' in Freemarker like this -

${hash['firstname']}
${hash['lastname']}

Output :

a
b

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiontzadorView Question on Stackoverflow
Solution 1 - JavaskaffmanView Answer on Stackoverflow
Solution 2 - JavaNick SpacekView Answer on Stackoverflow
Solution 3 - JavaddekanyView Answer on Stackoverflow
Solution 4 - JavareesView Answer on Stackoverflow
Solution 5 - JavaTk421View Answer on Stackoverflow
Solution 6 - JavaOndra ŽižkaView Answer on Stackoverflow
Solution 7 - JavaAshish ChhabriaView Answer on Stackoverflow