Java FreeMarker:如何在实现TemplateDirectiveModel时将TemplateDirectiveBody获取为字符串?

Java FreeMarker:如何在实现TemplateDirectiveModel时将TemplateDirectiveBody获取为字符串?,java,templates,freemarker,Java,Templates,Freemarker,我正在创建一个自定义FreeMarker指令。作为实现的一部分,我希望访问execute方法中的自定义指令体。有没有办法从TemplateDirectiveBody或Environment env获取它 模板中的用法 <@loop>My name is ${name}</@loop> 我不希望使用以下内容来获取完整的模板字符串: Writer w = new StringWriter(); env.getCurrentTemplate().dump(w); 我假设问题

我正在创建一个自定义FreeMarker指令。作为实现的一部分,我希望访问execute方法中的自定义指令体。有没有办法从TemplateDirectiveBody或Environment env获取它

模板中的用法

<@loop>My name is ${name}</@loop>
我不希望使用以下内容来获取完整的模板字符串:

Writer w = new StringWriter();
env.getCurrentTemplate().dump(w);

我假设问题的关键是,您不希望解析
${name}
(否则您可以只使用
TemplateDirectiveBody
API)。你不应该这样做。但是,我认为,通过从
env.getCurrentDirectiveCallPlace()
获取源代码中的位置,您可以玩一个肮脏的把戏。现在您知道了需要删除原始源代码的哪一部分,尽管它将包括定界标记,因此您需要使用自己的程序逻辑删除这些标记(一点简化的解析…)。在获取模板的源代码时,理论上,
template
对象不应具有该属性。但由于一些不好的遗留问题,您得到了
Template.getSource(int,int,int,int)
。但是,它将用空格替换制表符,除非您在
配置中将
tabSize
设置为1。另一件要知道的事情是
Template.getSource
有点慢(在内存中复制字符有点浪费),而且每次都必须删除定界标记。但是速度问题也可以通过使用DirectiveCallPlace.getOrCreateCustomData来解决,它允许您缓存每个呼叫位置的最终
字符串。

感谢您的回复。是的,我不想解析
${name}
。当你说“你不应该这样做”,有什么具体的原因吗?我也想知道为什么这里不公开?getSource(int,int,int,int)对我没有帮助。我试图用我的自定义指令做的是避免嵌套,但允许重复。有效${abc}${xyz}无效${abc}${xyz}好吧,如果您指示模板语言替换一个值,那么禁止该行为是非常不寻常的,并且会让任何读取模板的人感到困惑(因为您已经更改了记录的行为)。但我不明白你想要实现什么。通过在运行时检查全局变量,可以禁止将
loop
嵌套到
loop
中。为什么这与不解析
${exp}
有关?AST API-s,特别是
getChildrenBuffer
,是低级实现细节。再次感谢您的回复。如何通过在运行时检查全局变量来禁止将
循环
嵌套到
循环
?我们接受来自用户的模板,因此作为一种安全措施,我希望避免无限循环或太多迭代。我正在创建一个自定义循环指令
,如
#list
,在这里我可以控制循环迭代的最大次数,也可以限制嵌套,即
。但是重复应该是有效的,就像
。你的确切意思是什么<代码>环境
具有
get/setGlobalVariable
方法。您可以在那里维护嵌套深度和迭代计数(甚至是总迭代计数,所以您不必禁止嵌套本身)。不过,全局变量也可以从模板中读取和写入。如果这是一个问题(或者仅仅需要更复杂的纯Java值),请使用
get/setCustomState
。还要注意,它需要依赖于一些内部API-s,但另一种可能是使模板执行可中断(通过
Thread.interrupt()
)。看看怎么做。如果您进入一个长时间运行的循环,您可以在中看到这一点。
Writer w = new StringWriter();
env.getCurrentTemplate().dump(w);