Freemarker: как выполнять итерацию по карте с помощью перечислений в виде ключей

Следующий код не работает, потому что 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 (i.e). Затем просто создайте экземпляр bean с помощью mapp и поместите 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;
    }
}

Это позволяет поместить Enum в вашу конфигурацию и перебрать все экземпляры.

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. Пока myMap[key] по-прежнему принимает строковый ключ (см. Часто задаваемые вопросы, почему), теперь можно использовать 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. Если вы используете чистую BeansWrapper (не рекомендуется!), Вам нечего делать, поскольку она всегда поддерживает эту функцию.