Freemarker: как перебирать карту, используя перечисления в качестве ключей

следующий код не работает, потому что Freemarker, похоже, передает значение выражения внутри [] в строку, а затем использует его в качестве ключа, что на самом деле не ожидается.

подготовка модели шаблона:

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

мой.ftl:

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

на документация Freemarker описано, как получить доступ к самому перечислению, но я ничего не нашел о том, как получить значение из хэша, используя перечисление в качестве ключ.

спасибо.

2 ответов


перефразируя Freemarker документация FAQ на этой

вы не можете использовать нестроковые ключи в выражении myMap[key]. Вы можете использовать методы!

таким образом, вы можете создать боб, который предоставляет вам способ добраться до вашего Java EnumMap, (i.e). Затем просто создайте экземпляр этого компонента с помощью mapp и поместите его в свою модель.

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 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.3.22. В то время как myMap[key] по-прежнему предполагает ключевую строку (см FAQ Запись Почему), теперь можно использовать myMap?api.get(key) как временное решение. Она нуждается в некоторой настройке:

  • прежде всего,?api по умолчанию запрещено, поэтому вам нужно установить api_builtin_enabled (Configuration.setAPIBuiltinEnabled(boolean)) параметр true.
  • затем object_wrapper (Configuration.setObjectWrapper(ObjectWrapper)) используется должен поддерживать эту функцию (подвергая API). Если вы не установите object_wrapper в любом месте, а затем просто увеличивая incompatible_improvements установки (Configuration параметр конструктора, или Configuration.setIncompatibleImprovements(Version)) до 2.3.22 решает это. Если вы установите object_wrapper (т. е. вы перезаписываете значение по умолчанию), и это DefaultObjectWrapper экземпляр, тогда обратите внимание, что DefaultObjectWrapper своя incompatibleImprovements свойство, которое должно быть установлено на 2.3.22. Если вы используете pure BeansWrapper (не рекомендуется!) тогда вам ничего не нужно делать, так как он всегда поддерживает эту функцию.