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

假如想象 提交于 2019-11-27 04:33:57

问题


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.


回答1:


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> 



回答2:


The accepted answer isn't the simplest solution since 2.3.22. While myMap[key] still assumes a string key (see FAQ entry why), now one can use myMap?api.get(key) as a workaround. It needs some configuring though:

  • First of all, ?api is disallowed by default, so you need to set the api_builtin_enabled (Configuration.setAPIBuiltinEnabled(boolean)) setting to true.
  • Then, the object_wrapper (Configuration.setObjectWrapper(ObjectWrapper)) used needs to support this feature (exposing the API). If you don't set the object_wrapper anywhere, then just increasing the incompatible_improvements setting (the Configuration constructor parameter, or Configuration.setIncompatibleImprovements(Version)) to 2.3.22 solves this. If you set the object_wrapper (i.e., you overwrite the default), and it's a DefaultObjectWrapper instance, then note that DefaultObjectWrapper has its own incompatibleImprovements property that has to be set to 2.3.22. If you are using pure BeansWrapper (not recommended!) then you have to do nothing, as it always supports this feature.


来源:https://stackoverflow.com/questions/5422412/freemarker-how-to-iterate-through-the-map-using-enums-as-keys

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!