groovy - 如何定义可以将类型传播到内部块的类型感知 groovy DSL?
问题描述
我正在尝试实现一个 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()
此处的文档建议仅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>")
任何人都可以帮忙吗?
解决方案
推荐阅读
- angular - Angular Material mat-checkbox 未显示
- haskell - 堆栈设置:在路径上找不到名为 git 的可执行文件
- javascript - 将块绑定到表格中的单元格
- mysql - 如何在 Mosaic 中创建与任何外部数据库的连接?
- ios - Unity - 分发构建崩溃 - EXC_BAD_ACCESS - KERN_INVALID_ADDRESS
- python - 无法以橙色运行主题建模 - 文本挖掘插件中不显示图标
- php - Laravel 在 Blade 上使用外键获取另一个表的值
- android - (已解决)getUid 只能从同一个库组中调用(groupId=com.google.firebase)
- c - 为什么当 mod 限制为 <=1 时它会返回零?
- android - 如何在 Android 中使用 Navigation Drawer