Freemarker从java.lang.Integer调用静态java方法



我有个问题。我想在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:

  1. 创建一个类,让我们称之为JSONObjectAdapter,它实现了TemplateHashModelEx2(或者,对于基本用例来说,简单得多的TemplateHashModel就足够了(。其中,在实现TemplateHashModel.get(String)时,必须调用JSONObject.has(key)来检查密钥是否存在,如果不存在,则返回null,否则继续调用JSONObject.get(key)

  2. 创建一个类,我们称之为DefaultObjectWrapperWithJSONSupport,它扩展了DefaultObjectWrapper。你的课应该用JSONObjectAdapter包装JSONObject-s。

  3. 如果您已经配置了FreeMarker(在每次模板处理之前NOT(,请将objectWrapper指定为DefaultObjectWrapperWithJSONSupport

正确地做上面的事情有一些不明显的地方,所以我强烈建议从这个例子开始:https://freemarker.apache.org/docs/pgui_datamodel_objectWrapper.html#pgui_datamodel_customObjectWrappingExample

上面链接的示例完成了上面的3个步骤,但支持Tupple类,而不是JSONObject。这是一个TemplateSequenceModel,而不是TemplateHashModel,但在其他方面必须做的非常相似。

最新更新