我有个问题。我想在freemaker模板中调用一个静态java方法Integer.toHexString()
。在我的代码中,我实现了以下几行:
....
cfg.setSharedVariable("Integer",BeansWrapper.getDefaultInstance().
getStaticModels().
get("java.lang.Integer");
....
);
我的模板看起来像这个
<#list Items.iterator() as var>
<#assign hex = Integer.toHexString(var) />
${hex}
</#list>
但如果我执行代码,我会得到以下错误:
freemarker.core._TemplateModelException: An error has occurred when reading existing sub-variable "Integer"; see cause exception! The type of the containing value was: extended_hash+string (org.json.JSONObject wrapped into f.e.b.StringModel)
----
FTL stack trace ("~" means nesting-related):
- Failed at: #assign hex = Integer.toHexString(var... [in template "decToHex.ftl"...]
我做错了什么?谢谢
根据错误消息,您的数据模型(也称为模板上下文(是org.json.JSONObject
。FreeMarker不知道API,但它发现JSONObject
有一个get(String)
方法,并尝试使用它。不幸的是,get
方法的行为与Map
风格的get(key)
不同。FreeMarker首先调用JSONObject.get("Integer")
来查看变量是否在数据模型中。如果不是,它希望返回一个null
,然后尝试从更高的作用域(如共享变量(获取它。但是JSONObject.get(String)
抛出JSONException
,而不是返回null
,这是您在错误日志中看到的(如果您查看整个堆栈跟踪,JSONException
应该作为原因异常出现(。
为了解决这个问题,你需要教FreeMarker如何处理JSONObject
-s:
-
创建一个类,让我们称之为
JSONObjectAdapter
,它实现了TemplateHashModelEx2
(或者,对于基本用例来说,简单得多的TemplateHashModel
就足够了(。其中,在实现TemplateHashModel.get(String)
时,必须调用JSONObject.has(key)
来检查密钥是否存在,如果不存在,则返回null
,否则继续调用JSONObject.get(key)
。 -
创建一个类,我们称之为
DefaultObjectWrapperWithJSONSupport
,它扩展了DefaultObjectWrapper
。你的课应该用JSONObjectAdapter
包装JSONObject
-s。 -
如果您已经配置了FreeMarker(在每次模板处理之前NOT(,请将
objectWrapper
指定为DefaultObjectWrapperWithJSONSupport
。
正确地做上面的事情有一些不明显的地方,所以我强烈建议从这个例子开始:https://freemarker.apache.org/docs/pgui_datamodel_objectWrapper.html#pgui_datamodel_customObjectWrappingExample
上面链接的示例完成了上面的3个步骤,但支持Tupple
类,而不是JSONObject
。这是一个TemplateSequenceModel
,而不是TemplateHashModel
,但在其他方面必须做的非常相似。