我正在尝试实现Groovy DSL,它在顶级块参数中获取类名,然后允许在内部块中针对该类的方法进行静态类型检查,而无需冗余地重新声明该类名
(我正在使用Groovy v2.5.6)
例如,给定此类:
// A message data type to parse
@Canonical
class MessageX {
int size
boolean hasName
// an optional field to read, depending on whether #hasName is true
String name
}
我希望能够在DSL中定义如下内容:
parserFor(MessageX) {
readInt 'size'
readBool 'hasName'
// #hasName is a property of MessageX
when { hasName } {
readString 'name'
}
}
尝试执行此操作可能是:
import groovy.transform.Canonical
import groovy.transform.CompileStatic
@CompileStatic
@Canonical
class MessageX {
boolean hasName
String name
int size
}
/** Generic message builder class for parsing messages */
@CompileStatic
class MessageBlock<T> {
MessageBlock(Map<String, Object> values) {
this.value = values
}
private final Map<String, Object> value
void readString(String field) {
// ...
}
void readInt(String field) {
// ..
}
void readBool(String field) {
// ...
}
/** Defines a condition */
void when(@DelegatesTo(type = "T") Closure conditionBlock, @DelegatesTo(value = MessageBlock, type = "MessageBlock<T>") Closure bodyBlock) {
// ...
}
}
@CompileStatic
class Parser {
static final <T> Closure<T> parserFor(Class<T> type, @DelegatesTo(value = MessageBlock, type = "MessageBlock<T>") Closure block) {
println "parser get type $type.name"
return {
Map<String, Object> values = [:]
MessageBlock<T> blockImpl = new MessageBlock<T>(values);
block.delegate = blockImpl
block()
return type.newInstance(values)
}
}
static void build() {
// Define a parser using our DSL
Closure<MessageX> messageXParser = parserFor(MessageX) {
readBool 'hasName'
when { hasName } {
readString 'name'
}
}
messageXParser()
}
}
Parser.build()
文档here建议仅通过type = "MessageBlock<T>"
上的DelegatesTo
标记就可以实现。
但是,这使我在编译时出现了空指针异常。
Caught: BUG! exception in phase 'instruction selection' in source unit 'test.groovy' unexpected NullpointerException
BUG! exception in phase 'instruction selection' in source unit 'test.groovy' unexpected NullpointerException
Caused by: java.lang.NullPointerException
在上面的示例中,我还具有value = MessageBlock
标签,该标签至少避免了NPE-但仍然出现错误:
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
test.groovy: 57: [Static type checking] - The variable [hasName] is undeclared.
@ line 57, column 20.
when { hasName } {
^
我还没有找到一种方法来获取#when
方法的闭包块以正确地委派给MessageX
类。我已经尝试将这些注释用于#parserFor
的第二个参数以及其他各种排列,但无济于事:
DelegatesTo(MessageX)
DelegatesTo(value = MessageX, type = "T")
DelegatesTo(value = MessageX, type = "MessageX<T>")
DelegatesTo(type = "MessageX<T>")
有人可以帮忙吗?