有趣的问题。该插件使用 Groovy 元编程将这些属性(主要、次要、补丁...)添加到版本属性。
据我所知,Kotlin 无法访问 Groovy 的 MetaClass 属性。
插件应该对版本属性使用普通的类结构,或者(希望将版本保留为 String 对象)向项目添加一个专用属性,其中包含这些值作为新类的属性。但目前的实现似乎与 Gradle Kotlin DSL 不兼容。
这是他们设置project.version
属性并将属性添加到其 MetaClass 的代码部分(源代码):
project.version = semanticBuildVersion as String
// Attach snapshot boolean-property to version - says whether version is snapshot or not
project.version.metaClass.snapshot = semanticBuildVersion.snapshot
// Attach version components
def versionComponents = project.version.split(/[.-]/, 4)
project.version.metaClass.major = versionComponents[VersionComponent.MAJOR.index] as int
project.version.metaClass.minor = versionComponents[VersionComponent.MINOR.index] as int
project.version.metaClass.patch = versionComponents[VersionComponent.PATCH.index] as int
Groovy 官方文档实际上记录了运行时元编程对于其他 JVM 语言是不可见的,而编译时元编程是可见的(链接):
Groovy 中的编译时元编程允许在编译时生成代码。这些转换正在改变程序的抽象语法树 (AST),这就是为什么在 Groovy 中我们将其称为 AST 转换。AST 转换允许您连接到编译过程,修改 AST 并继续编译过程以生成常规字节码。与运行时元编程相比,这具有使更改在类文件本身(也就是说,在字节码中)可见的优点。使其在字节码中可见很重要,例如,如果您希望转换成为类契约的一部分(实现接口、扩展抽象类……),或者即使您需要可以从 Java(或其他 JVM 语言)调用您的类)。例如,AST 转换可以向类添加方法。如果您使用运行时元编程来执行此操作,那么新方法将仅在 Groovy 中可见。如果您使用编译时元编程来做同样的事情,那么该方法也可以从 Java 中看到。最后但同样重要的是,编译时元编程的性能可能会更好(因为不需要初始化阶段)。