我正在尝试动态创建一个Groovy类。我使用GroovyClassLoader和SimpleTemplateEngine来注入字段和方法定义并生成我的新类文本表示并将其传递给GroovyClassLOader.parseClass()。这适用于类字段,如果表示方法体的闭包被注入文本,也适用于方法。我的问题是我不知道如何将Groovy闭包转换为其文本表示。我在StackOverflow上找到了几个例子:
print the closure definition/source in Groovy
和
Getting the contents of closure, in groovy
但是这两个例子都给了我这个例外:
Caught: java.lang.NullPointerException: Cannot invoke method getDeclaredMethods() on null object
表示metaClass.classNode为null
这是我的剧本:
c1 = '{return p1 + p2}'
c2 = '{return p1 * p2}'
data = [fields: ['p1': 'int', 'p2':'int'], methods: ['m1': c1, 'm2':c2], name: 'Agent']
templateText = '''
class $name
{
<%fields.each {%> $it.value $it.key \n<% } %>
<%methods.each {%> def $it.key() $it.value \n<% } %>
}
'''
engine = new groovy.text.SimpleTemplateEngine()
template = engine.createTemplate(templateText)
result = template.make(data)
println result
GroovyClassLoader loader = new GroovyClassLoader()
Class cls = loader.parseClass(result.toString())
i = cls.newInstance()
i.p1 = 1
i.p2 = 2
i.setP2(10)
println i.m1()
println i.m2()
答案 0 :(得分:1)
使用你链接的第二个例子,我可以得到(我认为)工作:
import groovy.inspect.swingui.AstNodeToScriptVisitor
String method( Closure a ) {
new StringWriter().with { writer ->
a.metaClass.classNode.getDeclaredMethods("doCall")[0].code.visit new AstNodeToScriptVisitor( writer )
"{${writer.toString()}}"
}
}
c1 = {p1 + p2}
c2 = '{return p1 * p2}'
data = [fields: ['p1': 'int', 'p2':'int'], methods: ['m1': method( c1 ), 'm2':c2], name: 'Agent']
templateText = '''
class $name
{
<%fields.each {%> $it.value $it.key \n<% } %>
<%methods.each {%> def $it.key() $it.value \n<% } %>
}
'''
engine = new groovy.text.SimpleTemplateEngine()
template = engine.createTemplate(templateText)
result = template.make(data)
println result
GroovyClassLoader loader = new GroovyClassLoader()
Class cls = loader.parseClass(result.toString())
i = cls.newInstance()
i.p1 = 1
i.p2 = 2
i.setP2(10)
println i.m1()
println i.m2()
它在GroovyConsole中不起作用,但如果将其保存为脚本并从命令行调用它,则它可以正常工作