1

In Apache OfBiz application, I have such code in controller:

   public static String runRequest(HttpServletRequest request, HttpServletResponse response) {
        Map<String, Long> typesToCount = getTypesToCount();
        request.setAttribute("types", typesToCount);
        return HttpFinals.RETURN_SUCCESS;
   }

And in freemarker template it's processed/iterated like so:

<table
<#list requestAttributes.types as key, value>
    <tr>
        <td>${key}</td>
        <td>${value}</td>
    </tr>
</#list>
</table>

On rendered html page I'm getting both actual map's string key's and map's methods names (put, remove, add etc.).

As for values they are not rendered at all the with following error:

FreeMarker template error: For "${...}" content: Expected a string or something automatically convertible to string (number, date or boolean), or "template output" , but this has evaluated to a method+sequence (wrapper: f.e.b.SimpleMethodModel)

I'm using freemarker 2.3.28

srzhio
  • 186
  • 2
  • 12

3 Answers3

3

Map.entrySet() method returns a collection (Set<Map.Entry<K, V>>) of the mappings contained in this map. So we can iterate over key-value pair using getKey() and getValue() methods of Map.Entry<K, V>. This method is most common and should be used if you need both map keys and values in the loop.

Try this code to iterate through the values in FTL

<table>
  <#list requestAttributes.entrySet() as requestAttribute>
  <tr>
    <td>${requestAttribute.getKey()}</td>
    <td>${requestAttribute.getValue()}</td>
  </tr>
  </#list>
</table>
2

Basically, I managed to iterate through the map only after wrapping it in SimpleMapModel like so:

   public static String runRequest(HttpServletRequest request, HttpServletResponse response) {
       Map<String, Long> typesToCount = getTypesToCount();
       request.setAttribute("types",  new SimpleMapModel(typesToCount, new DefaultObjectWrapper())));
       return HttpFinals.RETURN_SUCCESS;
    }

and int ftl template:

   <#list requestAttributes.types?keys as key>
   <tr>
       <td>${key}</td>
       <td>${requestAttributes.types[key]}</td>
   </tr>
   </#list>
srzhio
  • 186
  • 2
  • 12
1

That works like that if FreeMarker is configured to use a pure BeansWrapper (as opposed to DefaultObjectWrapper) for its object_wrapper setting, and the BeansWrapper.simpleMapWrapper property is left on its default value, false. Needless to say, it's a quite problematic configuration to work with. Hopefully it isn't the default of OfBiz. Although for old frameworks this can happen, as many many years ago this was a way of working around some limitations of FreeMarker, since this way you can just use the Java API of Map. Later, the introduction of the ?api built-in has made this hack needless.

ddekany
  • 29,656
  • 4
  • 57
  • 64