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
(не рекомендуется!), Вам нечего делать, поскольку она всегда поддерживает эту функцию.