Janith
Janith

Reputation: 365

unwanted values returning in Freemarker iterating maps

When iterating map

<#list map?keys as key> ${key} </#list>

will return clone,1,getKey,5,etc

Anyone have solution instead of removing unwanted value one by one ?

Upvotes: 2

Views: 787

Answers (2)

ddekany
ddekany

Reputation: 31152

You get both methods and keys mixed, if I understand well. This depends on the object_wrapper configuration setting (Configuration.setObjectWrapper(ObjectWrapper)). If you are using a BeansWrapper as the object_wrapper (as opposed to DefaultObjectWrapper, which never had this problem), this can be prevented by yourBeansWrapper.setSimpleMapWrapper(true). However, it's maybe not accidental that in that project it's false. There's a problem that FreeMarker language doesn't have a map type. It has something called hash, and that only supports string keys (sub-variables). So people may just use the Java API of java.util.Map-s instead of hash operators like [], ?keys, etc., and for that setSimpleMapWrapper(false) is needed, otherwise you don't see the Map methods. Then you should write map.keySet().

Update: In 2.3.22 and later, nobody is forced to use mixed methods and keys anymore (which was a rather confusing workaround even back then), as the Java methods (and Java Bean properties) are accessible in a separate namespace through ?api, like myMap?api.get(nonStringKey), myMap?api.keySet() etc. So you can use an ObjectWrapper that exposes the Map keys only and supports the ?api feature (preferably object_wrapper=DefaultObjectWrapper(2.3.22)), enable ?api (api_builtin_enabled=true; by default it's disallowed for backward-security), then just use ?api when you need something from the Java API namespace, and otherwise use [], ?keys, etc. if your Map keys are String-s.

Upvotes: 4

Satheesh Cheveri
Satheesh Cheveri

Reputation: 3679

Try with below syntax

<#assign keys = map?keys>
<#list keys as key>${key} = ${h[key]}; </#list>

See the link

EDIT -Extending @ddekany answer,

you would need to handle this in the code where you parse/invoke the FTL, some thing like below( just sample code). It could have been better ff you can add the FTL processing code here.

 BeansWrapper ow = new BeansWrapper();
  ow.setExposeFields(true);
 // ow.setSimpleMapWrapper(true);

  Template template = freeMarkerConfiguration.getTemplate(templateName, locale);
  template.setObjectWrapper(ow);
  template.process(root, writer);

Upvotes: 1

Related Questions