Groovy插件扩展了Java插件,以添加对Groovy项目的支持. 它可以处理Groovy代码,混合的Groovy和Java代码,甚至是纯Java代码(尽管我们不一定建议在后者中使用它). 该插件支持联合编译 ,可让您自由混合并匹配Groovy和Java代码,并具有双向依赖性. 例如,Groovy类可以扩展Java类,而Java类又可以扩展Groovy类. 这样就可以为作业使用最佳语言,并在需要时用其他语言重写任何类.

请注意,如果您想从API /实现分离中受益,您还可以将java-library插件应用于Groovy项目.

Usage

要使用Groovy插件,请在构建脚本中包含以下内容:

例子1.使用Groovy插件
build.gradle
plugins {
    id 'groovy'
}
build.gradle.kts
plugins {
    groovy
}

Tasks

Groovy插件将以下任务添加到项目中.

compileGroovyGroovyCompile

依赖于取决于: compileJava

编译生产Groovy源文件.

compileTestGroovyGroovyCompile

依赖于取决于: compileTestJava

编译测试Groovy源文件.

compileSourceSetGroovyGroovyCompile

依赖于取决于: compileSourceSetJava

编译给定源集的Groovy源文件.

groovydocGroovydoc

为生产Groovy源文件生成API文档.

Groovy插件将以下依赖项添加到Java插件添加的任务中.

表1. Groovy插件-其他任务依赖性
任务名称 依赖于取决于

classes

compileGroovy

testClasses

compileTestGroovy

sourceSetClasses

compileSourceSetGroovy

groovyPluginTasks
图1. Groovy插件-任务

Project layout

The Groovy plugin assumes the project layout shown in Groovy Layout. All the Groovy source directories can contain Groovy and Java code. The Java source directories may only contain Java source code.[1] None of these directories need to exist or have anything in them; the Groovy plugin will simply compile whatever it finds.

src/main/java

生产Java源代码.

src/main/resources

生产资源,例如XML和属性文件.

src/main/groovy

生产Groovy源. 也可能包含Java源文件以进行联合编译.

src/test/java

测试Java源代码.

src/test/resources

测试资源.

src/test/groovy

测试Groovy源. 也可能包含Java源文件以进行联合编译.

src/sourceSet/java

名为sourceSet的源集的Java源.

src/sourceSet/resources

名为sourceSet的源集的资源.

src/sourceSet/groovy

给定源集的Groovy源文件. 也可能包含Java源文件以进行联合编译.

Changing the project layout

就像Java插件一样,Groovy插件允许您配置Groovy生产和测试源文件的自定义位置.

示例2.自定义Groovy源布局
build.gradle
sourceSets {
    main {
        groovy {
            srcDirs = ['src/groovy']
        }
    }

    test {
        groovy {
            srcDirs = ['test/groovy']
        }
    }
}
build.gradle.kts
sourceSets {
    main {
        withConvention(GroovySourceSet::class) {
            groovy {
                setSrcDirs(listOf("src/groovy"))
            }
        }
    }

    test {
        withConvention(GroovySourceSet::class) {
            groovy {
                setSrcDirs(listOf("test/groovy"))
            }
        }
    }
}

Dependency management

因为Gradle的构建语言是基于Groovy的,并且Gradle的某些部分是在Groovy中实现的,所以Gradle已经附带了Groovy库. 尽管如此,Groovy项目仍需要显式声明一个Groovy依赖项. 然后,将在编译和运行时类路径上使用此依赖项. 它还将分别用于获取Groovy编译器和Groovydoc工具.

如果将Groovy用于生产代码,则应将Groovy依赖项添加到implementation配置中:

例子3. Groovy依赖的配置
build.gradle
repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.codehaus.groovy:groovy-all:2.4.15'
}
build.gradle.kts
repositories {
    mavenCentral()
}

dependencies {
    implementation("org.codehaus.groovy:groovy-all:2.4.15")
}

如果Groovy仅用于测试代码,则应将Groovy依赖项添加到testImplementation配置中:

示例4. Groovy测试依赖项的配置
build.gradle
dependencies {
    testImplementation 'org.codehaus.groovy:groovy-all:2.4.15'
}
build.gradle.kts
dependencies {
    testImplementation("org.codehaus.groovy:groovy-all:2.4.15")
}

要使用Gradle附带的Groovy库,请声明一个localGroovy()依赖项. 请注意,不同的Gradle版本附带了不同的Groovy版本. 因此,使用localGroovy()声明常规的Groovy依赖项安全性低.

例子5.捆绑的Groovy依赖项的配置
build.gradle
dependencies {
    implementation localGroovy()
}
build.gradle.kts
dependencies {
    implementation(localGroovy())
}

Groovy库不一定必须来自远程存储库. 它也可能来自本地lib目录,可能已签到源代码管理:

示例6. Groovy文件依赖项的配置
build.gradle
repositories {
    flatDir { dirs 'lib' }
}

dependencies {
    implementation module('org.codehaus.groovy:groovy:2.4.15') {
        dependency('org.ow2.asm:asm-all:5.0.3')
        dependency('antlr:antlr:2.7.7')
        dependency('commons-cli:commons-cli:1.2')
        module('org.apache.ant:ant:1.9.4') {
            dependencies('org.apache.ant:ant-junit:1.9.4@jar',
                         'org.apache.ant:ant-launcher:1.9.4')
        }
    }
}
build.gradle.kts
repositories {
    flatDir { dirs("lib") }
}

dependencies {
    implementation(module("org.codehaus.groovy:groovy:2.4.15") {
        dependency("org.ow2.asm:asm-all:5.0.3")
        dependency("antlr:antlr:2.7.7")
        dependency("commons-cli:commons-cli:1.2")
        module("org.apache.ant:ant:1.9.4") {
            dependencies("org.apache.ant:ant-junit:1.9.4@jar",
                         "org.apache.ant:ant-launcher:1.9.4")
        }
    })
}

Automatic configuration of groovyClasspath

GroovyCompileGroovydoc任务以两种方式使用Groovy代码:在其classpath ,以及在其groovyClasspath . 前者用于查找源代码引用的类,通常将包含Groovy库以及其他库. 后者分别用于加载和执行Groovy编译器和Groovydoc工具,并且应仅包含Groovy库及其依赖项.

除非显式配置任务的groovyClasspath否则Groovy(基本)插件将尝试从任务的classpath推断出它. 这样做如下:

  • 如果在classpath上找到了一个groovy-all(-indy) Jar,则该jar将添加到groovyClasspath .

  • 如果在classpath上找到一个groovy(-indy) jar,并且该项目至少声明了一个存储库, groovy(-indy)相应的groovy(-indy)存储库依赖项添加到groovyClasspath .

  • 否则,任务的执行将失败,并显示一条消息, groovyClasspath无法推断groovyClasspath .

请注意,每个jar的" -indy "变体是指具有invokedynamic支持的版本.

Convention properties

Groovy插件不会向项目添加任何约定属性.

Source set properties

Groovy插件将以下约定属性添加到项目中的每个源集. 您可以在构建脚本中使用这些属性,就像它们是源集对象的属性一样.

Groovy Plugin — source set properties

groovySourceDirectorySet (read-only)

默认值 :不为空

此源集的Groovy源文件. 包含在Groovy源目录中找到的所有.groovy.java文件,并且排除所有其他类型的文件.

groovy.srcDirsSet<File>

默认值: [projectDir/src/name/groovy]

包含此源集的Groovy源文件的源目录. 也可能包含Java源文件以进行联合编译. 可以使用" 指定多个文件"中所述的任何内容进行设置.

allGroovyFileTree (read-only)

默认值 :不为空

该源集的所有Groovy源文件. 仅包含在Groovy源目录中找到的.groovy文件.

这些属性由GroovySourceSet类型的约定对象提供.

The Groovy plugin also modifies some source set properties:

Groovy Plugin - modified source set properties

物业名称 Change

allJava

添加在Groovy源目录中找到的所有.java文件.

allSource

添加在Groovy源目录中找到的所有源文件.

GroovyCompile

Groovy插件为项目中的每个源集添加了一个GroovyCompile任务. 任务类型扩展了JavaCompile任务(请参阅相关的Java插件部分 ). GroovyCompile任务支持官方Groovy编译器的大多数配置选项.

表2. Groovy插件-GroovyCompile属性
任务属性 Type 默认值

classpath

FileCollection

sourceSet.compileClasspath

source

FileTree . 可以使用" 指定多个文件"中所述的任何内容进行设置.

sourceSet.groovy

destinationDir

File.

sourceSet.groovy.outputDir

groovyClasspath

FileCollection

groovy配置,如果非空; 否则在classpath找到Groovy库

Compilation avoidance

注意:自Gradle 5.6起,避免Groovy编译是一个令人振奋的功能. 存在已知的错误,因此请自行承担风险.

要启用避免Groovy编译的孵化支持,请将enableFeaturePreview添加到您的设置文件:

settings.gradle
enableFeaturePreview('GROOVY_COMPILATION_AVOIDANCE')
settings.gradle.kts
enableFeaturePreview("GROOVY_COMPILATION_AVOIDANCE")

如果从属项目以与ABI兼容的方式进行了更改(仅更改了其专用API),那么Groovy编译任务将是最新的. 这意味着,如果项目A取决于项目B和类B在ABI兼容的方式被改变(典型地,仅改变一个方法的主体),则摇篮不会重新编译A .

有关不影响ABI且被忽略的更改类型的详细列表,请参见Java避免编译 .

但是,类似于Java的注释处理,有多种方法可以定制Groovy编译过程 ,而实现细节很重要. 一些著名的例子是Groovy AST转换 . 在这些情况下,必须在称为astTransformationClasspath的类路径中分别声明这些依赖astTransformationClasspath

例子7.声明AST转换
build.gradle
    configurations { astTransformation }
    dependencies {
        astTransformation(project(":astTransformation"))
    }
    tasks.withType(GroovyCompile).configureEach {
        astTranformationClasspath.from(configurations.astTransformation)
    }
build.gradle.kts
    val astTransformation by configurations.creating
    dependencies {
        astTransformation(project(":astTransformation"))
    }
    tasks.withType<GroovyCompile>().configureEach {
        astTranformationClasspath.from(astTransformation)
    }

Incremental Groovy compilation

从5.6开始,Gradle引入了实验性的Groovy增量编译器. 要为Groovy启用增量编译,您需要:

示例8.启用增量Groovy编译
build.gradle
    tasks.withType(GroovyCompile).configureEach {
        options.incremental = true
    }
build.gradle.kts
    tasks.withType<GroovyCompile>().configureEach {
        options.isIncremental = true
    }

这为您带来以下好处:

  • 增量构建要快得多.

  • 如果仅更改了少量Groovy源文件,则仅重新编译受影响的源文件. 不需要重新编译的类在输出目录中保持不变. 例如,如果仅更改几个Groovy测试类,则无需重新编译所有Groovy测试源文件-仅需要重新编译更改的文件.

要了解增量编译的工作原理,请参见增量Java编译以获取详细概述. 请注意,与Java增量编译有一些区别:

  • 与Java不同,Groovy编译器不内联常量,因此对常量的更改不会触发完整的重新编译.

  • Groovy编译器不会将@Retention保留在生成的注释类字节码( GROOVY-9185 )中,因此所有注释均为RUNTIME . 这意味着对源保留批注的更改将不会触发完全重新编译.

Known issues

  • 对资源的更改不会触发重新编译,这可能会导致某些不正确的情况,例如扩展模块 .

Compiling and testing for Java 6 or Java 7

Groovy编译器将始终与用于启动Gradle的Java版本一起执行. 您应该将sourceCompatibilitytargetCompatibility设置为1.61.7 . 如果您还具有Java源文件,则可以按照与Java插件相同的步骤进行操作,以确保使用正确的Java编译器.

Example: Configure Java 6 build for Groovy

gradle.properties
# in $HOME/.gradle/gradle.properties
java6Home=/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
build.gradle
java {
    sourceCompatibility = JavaVersion.VERSION_1_6
    targetCompatibility = JavaVersion.VERSION_1_6
}

assert hasProperty('java6Home') : "Set the property 'java6Home' in your your gradle.properties pointing to a Java 6 installation"
def javaExecutablesPath = new File(java6Home, 'bin')
def javaExecutables = [:].withDefault { execName ->
    def executable = new File(javaExecutablesPath, execName)
    assert executable.exists() : "There is no $execName executable in $javaExecutablesPath"
    executable
}
tasks.withType(AbstractCompile) {
    options.with {
        fork = true
        forkOptions.javaHome = file(java6Home)
    }
}
tasks.withType(Javadoc) {
    executable = javaExecutables.javadoc
}
tasks.withType(Test) {
    executable = javaExecutables.java
}
tasks.withType(JavaExec) {
    executable = javaExecutables.java
}
build.gradle.kts
java {
    sourceCompatibility = JavaVersion.VERSION_1_6
    targetCompatibility = JavaVersion.VERSION_1_6
}

require(hasProperty("java6Home")) { "Set the property 'java6Home' in your your gradle.properties pointing to a Java 6 installation" }
val java6Home: String by project
val javaExecutablesPath = File(java6Home, "bin")
fun javaExecutable(execName: String): String {
    val executable = File(javaExecutablesPath, execName)
    require(executable.exists()) { "There is no $execName executable in $javaExecutablesPath" }
    return executable.toString()
}
tasks.withType<JavaCompile>().configureEach {
    options.apply {
        isFork = true
        forkOptions.javaHome = file(java6Home)
    }
}
tasks.withType<Javadoc>().configureEach {
    executable = javaExecutable("javadoc")
}
tasks.withType<Test>().configureEach {
    executable = javaExecutable("java")
}
tasks.withType<JavaExec>.configureEach {
    executable = javaExecutable("java")
}

1 . Gradle使用与Russel Winder的Gant工具引入的约定相同的约定.