StreamingTemplateEngine异常MissingPropertyException

时间:2018-05-14 16:31:29

标签: groovy

如果在Map中没有来自模板的参数并且将未找到的值替换为null时,如何避免出现MissingPropertyException?

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)
    }
}

2 个答案:

答案 0 :(得分:2)

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

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

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

解决方案:为Map

创建包装器

让我们解决它。我们将通过以总是返回containsKey(Object key)的方式覆盖map方法true来完成它(此方法由模板引擎使用,如果它返回false,则模板引擎会抛出异常) 。我们将创建一个封装类,它封装一个map并将非现有方法的调用委托给这个包装类。我们将此课程称为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.

希望它有所帮助。

答案 1 :(得分:2)

作为替代方案,您可以使用groovy 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.

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

虽然事后看来它远非完美。用更好的内部方法写另一个已经列入我的永恒列表。