Freemarker: How to iterate through the Map using enums as keys

Alex Vayda picture Alex Vayda · Mar 24, 2011 · Viewed 12.1k times · Source

The following code does not work because Freemarker seems to cast the value of the expression inside [] to String and then to use it as a key, which is not what is actually expected.

Preparing a template model:

Map<MyEnum, Object> myMap;
myMap.put(MyEnum.FOO, "Foo");
myMap.put(MyEnum.BAR, "Bar");
templateModel.put("myMap", myMap);

my.ftl:

<#list myMap?keys as key>
    <#assign value = myMap[key]>
    <li>${key} = ${value}</li>
</#list>

In the Freemarker documentation it is described how to access the Enum itself, but I didn't find anything about how to get a value from a hash using Enum as a key.

Thank you.

Answer

Andy picture Andy · Mar 26, 2011

To paraphrase Freemarker Documentation FAQ on this,

You can't use non-string keys in the myMap[key] expression. You can use methods!

So, you could create a bean that provides a way for you to get to your Java EnumMap, (i.e). Then just instantiate this bean with your mapp, and put the bean in your Model.

class EnumMap
{
    HashMap<MyEnum, String> map = new HashMap<MyEnum, String>();

    public String getValue(MyEnum e)
    {
        return map.get(e);
    }    
    ..constructor, generics, getters, setters left out.
}

I'm a little bit confused about what general goal your trying to accomplish. If you just need to list out the values of the enum (or perhaps a display value for each one). There is a much easier way to do it.

One way I've seen this problem solved is by putting a display value on the Enum instances.

i.e

enum MyEnum 
{   FOO("Foo"), 
    BAR_EXAMPLE("Bar Example"); 
    private String displayValue;

    MyEnum(String displayValue)
    {
        this.displayValue = displayValue;
    }

    public String getDisplay()
    {
        return displayValue;
    }
}

This allows you to put the Enum itself into your configuration, and iterate over all instances.

SimpleHash globalModel = new SimpleHash();
TemplateHashModel enumModels = BeansWrapper.getDefaultInstance().getEnumModels();
TemplateHashModel myEnumModel = (TemplateHashModel) enumModels.get("your.fully.qualified.enum.MyEnum");

globalModel.put("MyEnum", myEnumModel);
freemarkerConfiguration.setAllSharedVariables(globalModel);

Then you can iterate over the enum,

<#list MyEnum?values as item>
    ${item.display}
</#list>