自由标记:如何使用枚举作为键循环访问 Map

2022-09-04 20:43:57

下面的代码不起作用,因为 Freemarker 似乎将 [] 中的表达式的值强制转换为 String,然后将其用作键,这不是实际预期的。

准备模板模型:

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>

Freemarker文档中,描述了如何访问Enum本身,但我没有找到有关如何使用Enum作为键从哈希中获取值的任何信息。

谢谢。


答案 1

要解释Freemarker文档常见问题解答

不能在 myMap[key] 表达式中使用非字符串键。您可以使用方法!

因此,您可以创建一个bean,它为您提供了一种访问Java EnumMap的方法(即)。然后,只需使用映射实例化此 Bean,并将该 Bean 放入模型中。

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.
}

我对你试图实现的总体目标有点困惑。如果您只需要列出枚举的值(或者可能是每个枚举的显示值)。有一种更简单的方法可以做到这一点。

我看到这个问题解决的一种方法是在Enum实例上放置一个显示值。

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

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

    public String getDisplay()
    {
        return displayValue;
    }
}

这允许您将枚举本身放入配置中,并循环访问所有实例。

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);

然后,您可以迭代枚举,

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

答案 2

自2.3.22以来,接受的答案并不是最简单的解决方案。虽然仍然假定字符串键(请参阅 FAQ 条目为什么),但现在可以使用作为解决方法。它需要一些配置:myMap[key]myMap?api.get(key)

  • 首先,默认情况下不允许,因此您需要将()设置设置为。?apiapi_builtin_enabledConfiguration.setAPIBuiltinEnabled(boolean)true
  • 然后,使用的 () 需要支持此功能(公开 API)。如果您没有设置 anywhere,则只需将设置(构造函数参数或 )增加到 2.3.22 即可解决此问题。如果您设置了(即,您覆盖了默认值),并且它是一个实例,则请注意,它具有自己的属性,必须设置为2.3.22。如果您使用的是纯(不推荐!),那么您无需执行任何操作,因为它始终支持此功能。object_wrapperConfiguration.setObjectWrapper(ObjectWrapper)object_wrapperincompatible_improvementsConfigurationConfiguration.setIncompatibleImprovements(Version)object_wrapperDefaultObjectWrapperDefaultObjectWrapperincompatibleImprovementsBeansWrapper