我正在尝试定义用于构建特定于域的查询的DSL。 DSL是使用FactoryBuilderSupport实现的,所以它看起来像下面(缩写):
class QueryBuilder extends FactoryBuilderSupport {
{
registerFactory('query', new QueryFactory())
registerFactory('match', new QueryMatchFactory())
registerFactory('obj', new ObjFactory())
}
def propertyMissing(String name) {
//give user meaningful message about the bad 'name' here
}
}
如果我只是将它作为一个groovy脚本运行(在IntelliJ或其他任何东西中),这可以正常工作。脚本如下所示:
def bldr = new QueryBuilder()
def queryBuilder = bldr.query() {
match {
obj {
//More stuff in here
}
}
}
现在我真正想要的是从Web界面获取脚本并运行它。所以我的第一个镜头是创建一个委托脚本。无论出于何种原因,我不得不说delegate.query()而不仅仅是查询或忽略我的委托。这与我读到的文档相矛盾。
class DslEvaluator {
def evaluateDsl (dsl) {
QueryBuilder queryBuilder = new QueryBuilder()
def compilerConfiguration = new CompilerConfiguration()
compilerConfiguration.scriptBaseClass = DelegatingScript.class.name
def shell = new GroovyShell(this.class.classLoader, new Binding(), compilerConfiguration)
Script script = shell.parse("""
delegate.query() {
${dsl}
}
""")
script.setDelegate queryBuilder
script.run()
}
}
只要我没有定义propertyMissing方法,这就可以正常工作。如果我确定它,它会因某种原因被调用,这就是我看到的错误:
at com.xxx.xxx.site.dsl.QueryBuilder.propertyMissing(QueryBuilder.groovy:26)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
at groovy.lang.MetaClassImpl.invokeMissingProperty(MetaClassImpl.java:778)
at groovy.lang.MetaClassImpl.getProperty(MetaClassImpl.java:1731)
at groovy.lang.MetaClassImpl.getProperty(MetaClassImpl.java:3458)
at groovy.util.DelegatingScript.getProperty(DelegatingScript.java:102)
at org.codehaus.groovy.runtime.callsite.PogoGetPropertySite.getProperty(PogoGetPropertySite.java:47)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGroovyObjectGetProperty(AbstractCallSite.java:231)
at Script1.run(Script1.groovy:2)
at Script1$run.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112)
为了完整性,这里是测试用例。
@Test
void testEvaluateDsl() {
DslEvaluator dslEvaluator = new DslEvaluator()
dslEvaluator.evaluateDsl("""
match {
obj {
//more stuff in here
}
}
""")
}
那么如何处理添加propertyMissing()方法而不会失去在运行时作为脚本构建和执行它的能力呢?
答案 0 :(得分:0)
我想我现在可以回答我自己的问题了。
在仔细观察之后,我注意到了一些事情。
FactoryBuilderSupport扩展了Binding。因此,要将额外的变量绑定到脚本,我只需要在构建器实例上调用setVariable()。我可以通过任何AbstractFactory方法中的getVariable()方法访问绑定变量,因为它们都提供了构建器的实例。
我试图弄清楚如何在构建器上设置解析策略,所以我不需要在我的dsl中使用delegate.query。这是错误的做法。 FactoryBuilderSupport在其构建方法中获取脚本,并为我处理所有这些。一旦这样做,它还解决了无法提供propertyMissing()方法的问题。构建器还将在提供的脚本上调用run。
在一天结束时,这就是我现在所拥有的。
def evaluateDsl (dsl) {
QueryBuilder queryBuilder = new QueryBuilder()
def shell = new GroovyShell(this.class.classLoader, queryBuilder)
Script script = shell.parse("""
query() {
${dsl}
}
""")
Query query = queryBuilder.build(script)
query.toQueryString()
}