将已使用的类别设为@TypeChecked

时间:2016-06-21 15:57:02

标签: groovy dsl

是否可以让编译器知道在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.fromgroovy.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不会选择它。

1 个答案:

答案 0 :(得分:1)

不,@TypeChecked不支持类别。您可以使用extension module或撰写自己的type checked extensions