是否可以让编译器知道在groovy中执行闭包时使用的类别?
一个小例子:
class Example {
static time = evaluateTime {
println 1.minute.from.now
}
static def evaluateTime(Closure<Void> cl) {
GroovyUtil.use(TimeCategory, cl)
}
}
这在执行时工作正常,但IntelliJ会灰显minute
,如果我添加TypeChecked
注释,我会遇到编译错误。
@TypeChecked()
class Example {
static time = evaluateTime {
println 1.minute.from.now
}
static def evaluateTime(Closure<Void> cl) {
GroovyUtil.use(TimeCategory, cl)
}
}
在类似的情况下,我发现DelegatesTo
Annotation让编译器知道闭包是用不同的委托执行的,但我找不到使用Categories的相应Annotation。
关注Will P's advice我实施了一个小型POC扩展模块。
首先,我查看了涉及的类型
1
的类型为int
1.minute
的类型为groovy.time.TimeDuration
1.minute.from
是groovy.time.BaseDuration.From
groovy.time.BaseDuration.From
有一个now
属性(getNow
方法)因此我提出了这个扩展
class PrecompiledExtension extends GroovyTypeCheckingExtensionSupport.TypeCheckingDSL {
@Override
Object run() {
unresolvedProperty { pexp ->
if ('minute' == pexp.propertyAsString &&
getType(pexp.objectExpression) == classNodeFor(int)) {
storeType(pexp, classNodeFor(TimeDuration))
handled = true
}
if ('from' == pexp.propertyAsString &&
getType(pexp.objectExpression) == classNodeFor(TimeDuration)) {
storeType(pexp, classNodeFor(BaseDuration.From))
handled = true
}
}
}
}
它仅查看未解析的属性。
minute
,并且从中读取属性的表达式类型为int
,则结果将为TimeDuration
类型。from
,并且从中读取属性的表达式类型为TimeDuration
,则结果将为BaseDuration.From
类型。请注意,这只是一个POC。没有逻辑验证缺少的属性是在使用TimeCategory
调用的闭包中。
要让编译器使用扩展名,请将限定名称添加到TypeChecked
注释(下例中的type.PrecompiledExtension
)。请注意,使用TypeChecked
注释的类无法调用GroovyUtil.use
,因此我将调用移至基类。
class ExampleBase {
static def evaluateTime(@DelegatesTo(TimeCategory) Closure<Void> cl) {
GroovyUtil.use(TimeCategory, cl)
}
}
@TypeChecked(extensions = "type.PrecompiledExtension")
class Example extends ExampleBase {
static time = evaluateTime {
TimeDuration minute = 1.minute
BaseDuration.From from = minute.from
println 1.minute.from.now
}
}
请注意,type.PrecompiledExtension
类必须在Example
类之前编译。对于POC,我在第一次编译过程中禁用TypeChecked
,然后再次启用它以进行第二次传递。
这适用于编译器,但IntelliJ不会选择它。