流式处理模板引擎异常 缺少属性异常



如何避免在 Map 中的模板中缺少参数时发生 MissingPropertyException 并将未找到的值替换为 null?

import groovy.text.StreamingTemplateEngine
import groovy.text.Template
class Test {
private static Writable binding(Map map, String string) {
Template template = new StreamingTemplateEngine().createTemplate(string)
return template.make(map)
}
static void main(String... args) {
def template = "${test1} ${test2}"
def map = ["test1": "test1"]
print binding(map, template)
}
}

没有配置选项可以抑制此异常,但是您可以扩展传递给模板的映射并稍微更改其行为。请考虑以下示例:

import groovy.text.StreamingTemplateEngine
import groovy.text.Template
def string = '''
Dear <% out.print firstname %> ${lastname},
We <% if (accepted) out.print 'are pleased' else out.print 'regret' %> 
to inform you that your paper entitled
'$title' was ${ accepted ? 'accepted' : 'rejected' }.
The conference committee.
'''
def map = [
firstname: 'test',
lastname: 'test',
accepted: true
]
Template template = new StreamingTemplateEngine().createTemplate(string)
println template.make(map)

它失败,出现以下异常:

Caught: groovy.text.TemplateExecutionException: Template execution error at line 4:
3:     We <% if (accepted) out.print 'are pleased' else out.print 'regret' %>     to inform you that your paper entitled
--> 4:     '$title' was ${ accepted ? 'accepted' : 'rejected' }.
5:     
groovy.text.TemplateExecutionException: Template execution error at line 4:
3:     We <% if (accepted) out.print 'are pleased' else out.print 'regret' %>     to inform you that your paper entitled
--> 4:     '$title' was ${ accepted ? 'accepted' : 'rejected' }.
5:     
at test.run(test.groovy:21)
Caused by: groovy.lang.MissingPropertyException: No such property: title for class: groovy.tmp.templates.StreamingTemplateScript1
... 1 more

它失败了,因为我们从 3 个模板变量中定义了 4 个(缺少变量title(。

解决方案:为Map创建包装器

让我们修复它。我们将通过覆盖映射方法containsKey(Object key),使其始终返回true(此方法由模板引擎使用,如果它返回false,则模板引擎会抛出异常(。我们将创建一个包装类,该包装类封装映射并将不存在的方法的调用委托给这个包装类。我们将此类称为Bindings.

import groovy.text.StreamingTemplateEngine
import groovy.text.Template
class Bindings {
@Delegate private final Map map
Bindings(Map map) {
this.map = map
}
boolean containsKey(Object key) {
return true
}
}
def string = '''
Dear <% out.print firstname %> ${lastname},
We <% if (accepted) out.print 'are pleased' else out.print 'regret' %> 
to inform you that your paper entitled
'$title' was ${ accepted ? 'accepted' : 'rejected' }.
The conference committee.
'''
def map = [
firstname: 'test',
lastname: 'test',
accepted: true
]
Template template = new StreamingTemplateEngine().createTemplate(string)
println template.make(new Bindings(map))

输出:

Dear test test,
We are pleased 
to inform you that your paper entitled
'null' was accepted.
The conference committee.

不再抛出MissingPropertyException了。但是,如您所见,null在字符串中打印为null。如果要改为打印空字符串,可以添加Object get(Object key)方法Bindings并重写其默认行为:

class Bindings {
@Delegate private final Map map
Bindings(Map map) {
this.map = map
}
boolean containsKey(Object key) {
return true
}
Object get(Object key) {
return map.getOrDefault(key, '')
}
}

如果这样做,您将看到类似于以下内容的输出:

Dear test test,
We are pleased 
to inform you that your paper entitled
'' was accepted.
The conference committee.

希望对您有所帮助。

作为替代方案,您可以使用时髦的 Map.withDefault 方法:

import groovy.text.StreamingTemplateEngine
import groovy.text.Template
def string = '''
Dear <% out.print firstname %> ${lastname},
We <% if (accepted) out.print 'are pleased' else out.print 'regret' %> 
to inform you that your paper entitled
'$title' was ${ accepted ? 'accepted' : 'rejected' }.
The conference committee.
'''
def map = [
firstname: 'test',
lastname: 'test',
accepted: true
].withDefault { "<not found>" }
Template template = new StreamingTemplateEngine().createTemplate(string)
println template.make(map)

其中对 OPs 代码的唯一更改是withDefault子句。执行上述打印:

~> groovy test.groovy
Dear test test,
We are pleased
to inform you that your paper entitled
'<not found>' was accepted.
The conference committee.

作为旁注,我编写了流式模板引擎,作为对几年前其他模板引擎局限性的贡献和回应。很高兴看到它被使用!

虽然事后看来,它远非完美。用更好的内部方法写另一个已经在我的日子清单上。

相关内容

最新更新