Chapter 23. The Java Plugin

The Java plugin adds Java compilation, testing and bundling capabilities to a project. It serves as the basis for many of the other Gradle plugins.

23.1. Usage

To use the Java plugin, include in your build script:

Example 23.1. Using the Java plugin

build.gradle

apply plugin: 'java'

23.2. Source sets

The Java plugin introduces the concept of a source set. A source set is simply a group of source files which are compiled and executed together. These source files may include Java source files and resource files. Other plugins add the ability to include Groovy and Scala source files in a source set. A source set has an associated compile classpath, and runtime classpath.

One use for source sets is to group source files into logical groups which describe their purpose. For example, you might use a source set to define an integration test suite, or you might use separate source sets to define the API and implementation classes of your project.

The Java plugin defines two standard source sets, called main and test. The main source set contains your production source code, which is compiled and assembled into a JAR file. The test source set contains your unit test source code, which is compiled and executed using JUnit or TestNG.

23.3. Tasks

The Java plugin adds a number of tasks to your project, as shown below.

Table 23.1. Java plugin - tasks

Task name Depends on Type Description
compileJava All tasks which produce the compile classpath. This includes the jar task for project dependencies included in the compile configuration. JavaCompile Compiles production Java source files using javac.
processResources - Copy Copies production resources into the production classes directory.
classes compileJava and processResources. Some plugins add additional compilation tasks. Task Assembles the production classes directory.
compileTestJava compile, plus all tasks which produce the test compile classpath. JavaCompile Compiles test Java source files using javac.
processTestResources - Copy Copies test resources into the test classes directory.
testClasses compileTestJava and processTestResources. Some plugins add additional test compilation tasks. Task Assembles the test classes directory.
jar compile Jar Assembles the JAR file
javadoc compile Javadoc Generates API documentation for the production Java source, using Javadoc
test compile, compileTest, plus all tasks which produce the test runtime classpath. Test Runs the unit tests using JUnit or TestNG.
uploadArchives The tasks which produce the artifacts in the archives configuration, including jar. Upload Uploads the artifacts in the archives configuration, including the JAR file.
clean - Delete Deletes the project build directory.
cleanTaskName - Delete Deletes the output files produced by the specified task. For example cleanJar will delete the JAR file created by the jar task, and cleanTest will delete the test results created by the test task.

For each source set you add to the project, the Java plugin adds the following compilation tasks:

Table 23.2. Java plugin - source set tasks

Task name Depends on Type Description
compileSourceSetJava All tasks which produce the source set's compile classpath. JavaCompile Compiles the given source set's Java source files using javac.
processSourceSetResources - Copy Copies the given source set's resources into the classes directory.
sourceSetClasses compileSourceSetJava and processSourceSetResources. Some plugins add additional compilation tasks for the source set. Task Assembles the given source set's classes directory.

The Java plugin also adds a number of tasks which form a lifecycle for the project:

Table 23.3. Java plugin - lifecycle tasks

Task name Depends on Type Description
assemble All archive tasks in the project, including jar. Some plugins add additional archive tasks to the project. Task Assembles all the archives in the project.
check All verification tasks in the project, including test. Some plugins add additional verification tasks to the project. Task Performs all verification tasks in the project.
build check and assemble Task Performs a full build of the project.
buildNeeded build and build tasks in all project lib dependencies of the testRuntime configuration. Task Performs a full build of the project and all projects it depends on.
buildDependents build and build tasks in all projects with a project lib dependency on this project in a testRuntime configuration. Task Performs a full build of the project and all projects which depend on it.
buildConfigurationName The tasks which produce the artifacts in configuration ConfigurationName. Task Assembles the artifacts in the specified configuration. The task is added by the Base plugin which is implicitly applied by the Java plugin.
uploadConfigurationName The tasks which uploads the artifacts in configuration ConfigurationName. Upload Assembles and uploads the artifacts in the specified configuration. The task is added by the Base plugin which is implicitly applied by the Java plugin.

The following diagram shows the relationships between these tasks.

Figure 23.1. Java plugin - tasks

Java plugin - tasks

23.4. Project layout

The Java plugin assumes the project layout shown below. None of these directories need exist or have anything in them. The Java plugin will compile whatever it finds, and handles anything which is missing.

Table 23.4. Java plugin - default project layout

Directory Meaning
src/main/java Production Java source
src/main/resources Production resources
src/test/java Test Java source
src/test/resources Test resources
src/sourceSet/java Java source for the given source set
src/sourceSet/resources Resources for the given source set

23.4.1. Changing the project layout

You configure the project layout by configuring the appropriate source set. This is discussed in more detail in the following sections. Here is a brief example which changes the main Java and resource source directories.

Example 23.2. Custom Java source layout

build.gradle

sourceSets {
    main {
        java {
            srcDir 'src/java'
        }
        resources {
            srcDir 'src/resources'
        }
    }
}

23.5. Dependency management

The Java plugin adds a number of dependency configurations to your project, as shown below. It assigns those configurations to tasks such as compileJava and test.

Table 23.5. Java plugin - dependency configurations

Name Extends Used by tasks Meaning
compile - compileJava Compile time dependencies
runtime compile - Runtime dependencies
testCompile compile compileTestJava Additional dependencies for compiling tests.
testRuntime runtime, testCompile test Additional dependencies for running tests only.
archives - uploadArchives Artifacts (e.g. jars) produced by this project.
default runtime - The default configuration used by a project dependency on this project. Contains the artifacts and dependencies required by this project at runtime.

Figure 23.2. Java plugin - dependency configurations

Java plugin - dependency configurations

For each source set you add to the project, the Java plugins adds the following dependency configurations:

Table 23.6. Java plugin - source set dependency configurations

Name Extends Used by tasks Meaning
sourceSetCompile - compileSourceSetJava Compile time dependencies for the given source set
sourceSetRuntime sourceSetCompile - Runtime time dependencies for the given source set

23.6. Convention properties

The Java plugin adds a number of convention properties to the project, shown below. You can use these properties in your build script as though they were properties of the project object (see Section 21.3, “Conventions”).

Table 23.7. Java plugin - directory properties

Property name Type Default value Description
reportsDirName String reports The name of the directory to generate reports into, relative to the build directory.
reportsDir File (read-only) buildDir/reportsDirName The directory to generate reports into.
testResultsDirName String test-results The name of the directory to generate test result .xml files into, relative to the build directory.
testResultsDir File (read-only) buildDir/testResultsDirName The directory to generate test result .xml files into.
testReportDirName String tests The name of the directory to generate the test report into, relative to the reports directory.
testReportDir File (read-only) reportsDir/testReportDirName The directory to generate the test report into.
libsDirName String libs The name of the directory to generate libraries into, relative to the build directory.
libsDir File (read-only) buildDir/libsDirName The directory to generate libraries into.
distsDirName String distributions The name of the directory to generate distributions into, relative to the build directory.
distsDir File (read-only) buildDir/distsDirName The directory to generate distributions into.
docsDirName String docs The name of the directory to generate documentation into, relative to the build directory.
docsDir File (read-only) buildDir/docsDirName The directory to generate documentation into.
dependencyCacheDirName String dependency-cache The name of the directory to use to cache source dependency information, relative to the build directory.
dependencyCacheDir File (read-only) buildDir/dependencyCacheDirName The directory to use to cache source dependency information.

Table 23.8. Java plugin - other properties

Property name Type Default value Description
sourceSets SourceSetContainer (read-only) Not null Contains the project's source sets.
sourceCompatibility JavaVersion. Can also set using a String or a Number, e.g. '1.5' or 1.5. Value of the current used JVM Java version compatibility to use when compiling Java source.
targetCompatibility JavaVersion. Can also set using a String or Number, e.g. '1.5' or 1.5. sourceCompatibility Java version to generate classes for.
archivesBaseName String projectName The basename to use for archives, such as JAR or ZIP files.
manifest Manifest an empty manifest The manifest to include in all JAR files.

These properties are provided by convention objects of type JavaPluginConvention, BasePluginConvention and ReportingBasePluginConvention.

23.7. Working with source sets

You can access the source sets of a project using the sourceSets property. This is a container for the project's source sets, of type SourceSetContainer. There is also a sourceSets { } script block, which you can pass a closure to configure the source set container. The source set container works pretty much the same way as other containers, such as tasks.

Example 23.3. Accessing a source set

build.gradle

// Various ways to access the main source set
println sourceSets.main.output.classesDir
println sourceSets['main'].output.classesDir
sourceSets {
    println main.output.classesDir
}
sourceSets {
    main {
        println output.classesDir
    }
}

// Iterate over the source sets
sourceSets.all {
    println name
}

To configure an existing source set, you simply use one of the above access methods to set the properties of the source set. The properties are described below. Here is an example which configures the main Java and resources directories:

Example 23.4. Configuring the source directories of a source set

build.gradle

sourceSets {
    main {
        java {
            srcDir 'src/java'
        }
        resources {
            srcDir 'src/resources'
        }
    }
}

23.7.1. Source set properties

The following table lists some of the important properties of a source set. You can find more details in the API documentation for SourceSet.

Table 23.9. Java plugin - source set properties

Property name Type Default value Description
name String (read-only) Not null The name of the source set, used to identify it.
output SourceSetOutput (read-only) Not null The output files of the source set, containing its compiled classes and resources.
output.classesDir File buildDir/classes/name The directory to generate the classes of this source set into.
output.resourcesDir File buildDir/resources/name The directory to generate the resources of this source set into.
compileClasspath FileCollection compileSourceSet configuration. The classpath to use when compiling the source files of this source set.
runtimeClasspath FileCollection output + runtimeSourceSet configuration. The classpath to use when executing the classes of this source set.
java SourceDirectorySet (read-only) Not null The Java source files of this source set. Contains only .java files found in the Java source directories, and excludes all other files.
java.srcDirs Set<File>. Can set using anything described in Section 16.5, “Specifying a set of input files”. [projectDir/src/name/java] The source directories containing the Java source files of this source set.
resources SourceDirectorySet (read-only) Not null The resources of this source set. Contains only resources, and excludes any .java files found in the resource source directories. Other plugins, such as the Groovy plugin, exclude additional types of files from this collection.
resources.srcDirs Set<File>. Can set using anything described in Section 16.5, “Specifying a set of input files”. [projectDir/src/name/resources] The source directories containing the resources of this source set.
allJava SourceDirectorySet (read-only) java All .java files of this source set. Some plugins, such as the Groovy plugin, add additional Java source files to this collection.
allSource SourceDirectorySet (read-only) resources + java All source files of this source set. This include all resource files and all Java source files. Some plugins, such as the Groovy plugin, add additional source files to this collection.

23.7.2. Defining new source sets

To define a new source set, you simply reference it in the sourceSets { } block. Here's an example:

Example 23.5. Defining a source set

build.gradle

sourceSets {
    intTest
}

When you define a new source set, the Java plugin adds some dependency configurations for the source set, as shown in Table 23.6, “Java plugin - source set dependency configurations”. You can use these configurations to define the compile and runtime dependencies of the source set.

Example 23.6. Defining source set dependencies

build.gradle

sourceSets {
    intTest
}

dependencies {
    intTestCompile 'junit:junit:4.11'
    intTestRuntime 'org.ow2.asm:asm-all:4.0'
}

The Java plugin also adds a number of tasks which assemble the classes for the source set, as shown in Table 23.2, “Java plugin - source set tasks”. For example, for a source set called intTest, you can run gradle intTestClasses to compile the int test classes.

Example 23.7. Compiling a source set

Output of gradle intTestClasses

> gradle intTestClasses
:compileIntTestJava
:processIntTestResources
:intTestClasses

BUILD SUCCESSFUL

Total time: 1 secs

23.7.3. Some source set examples

Adding a JAR containing the classes of a source set:

Example 23.8. Assembling a JAR for a source set

build.gradle

task intTestJar(type: Jar) {
    from sourceSets.intTest.output
}

Generating Javadoc for a source set:

Example 23.9. Generating the Javadoc for a source set

build.gradle

task intTestJavadoc(type: Javadoc) {
    source sourceSets.intTest.allJava
}

Adding a test suite to run the tests in a source set:

Example 23.10. Running tests in a source set

build.gradle

task intTest(type: Test) {
    testClassesDir = sourceSets.intTest.output.classesDir
    classpath = sourceSets.intTest.runtimeClasspath
}

23.8. Javadoc

The javadoc task is an instance of Javadoc. It supports the core javadoc options and the options of the standard doclet described in the reference documentation of the Javadoc executable. For a complete list of supported Javadoc options consult the API documentation of the following classes: CoreJavadocOptions and StandardJavadocDocletOptions.

Table 23.10. Java plugin - Javadoc properties

Task Property Type Default Value
classpath FileCollection sourceSets.main.output + sourceSets.main.compileClasspath
source FileTree. Can set using anything described in Section 16.5, “Specifying a set of input files”. sourceSets.main.allJava
destinationDir File docsDir/javadoc
title String The name and version of the project

23.9. Clean

The clean task is an instance of Delete. It simply removes the directory denoted by its dir property.

Table 23.11. Java plugin - Clean properties

Task Property Type Default Value
dir File buildDir

23.10. Resources

The Java plugin uses the Copy task for resource handling. It adds an instance for each source set in the project. You can find out more about the copy task in Section 16.6, “Copying files”.

Table 23.12. Java plugin - ProcessResources properties

Task Property Type Default Value
srcDirs Object. Can set using anything described in Section 16.5, “Specifying a set of input files”. sourceSet.resources
destinationDir File. Can set using anything described in Section 16.1, “Locating files”. sourceSet.output.resourcesDir

23.11. CompileJava

The Java plugin adds a JavaCompile instance for each source set in the project. Some of the most common configuration options are shown below.

Table 23.13. Java plugin - Compile properties

Task Property Type Default Value
classpath FileCollection sourceSet.compileClasspath
source FileTree. Can set using anything described in Section 16.5, “Specifying a set of input files”. sourceSet.java
destinationDir File. sourceSet.output.classesDir

The compile task delegates to Ant's javac task. Setting options.useAnt to false activates Gradle's direct compiler integration, bypassing the Ant task. In a future Gradle release, this will become the default.

By default, the Java compiler runs in the Gradle process. Setting options.fork to true causes compilation to occur in a separate process. In the case of the Ant javac task, this means that a new process will be forked for each compile task, which can slow down compilation. Conversely, Gradle's direct compiler integration (see above) will reuse the same compiler process as much as possible. In both cases, all fork options specified with options.forkOptions will be honored.

23.12. Test

The test task is an instance of Test. It automatically detects and executes all unit tests in the test source set. It also generates a report once test execution is complete. JUnit and TestNG are both supported. Have a look at Test for the complete API.

23.12.1. Test execution

Tests are executed in a separate JVM, isolated from the main build process. The Test task's API allows you some control over how this happens.

There are a number of properties which control how the test process is launched. This includes things such as system properties, JVM arguments, and the Java executable to use. The task also provides a debug property, which when set to true, starts the test process in debug mode, suspended and listening on port 5005. This makes it very easy to debug your tests. You may also enable this using a system property as specified below.

You can specify whether or not to execute your tests in parallel. Gradle provides parallel test execution by running multiple test processes concurrently. Each test process executes only a single test at a time, so you generally don't need to do anything special to your tests to take advantage of this. The maxParallelForks property specifies the maximum number of test processes to run at any given time. The default is 1, that is, do not execute the tests in parallel.

The test process sets the org.gradle.test.worker system property to a unique identifier for that test process, which you can use, for example, in files names or other resource identifiers.

You can specify that test processes should be restarted after it has executed a certain number of test classes. This can be a useful alternative to giving your test process a very large heap. The forkEvery property specifies the maximum number of test classes to execute in a test process. The default is to execute an unlimited number of tests in each test process.

The task has an ignoreFailures property to control the behavior when tests fail. Test always executes every test that it detects. It stops the build afterwards if ignoreFailures is false and there are failing tests. The default value of ignoreFailures is false.

The testLogging property allows to configure which test events are going to be logged and at which detail level. By default, a concise message will be logged for every failed test. See TestLoggingContainer for how to tune test logging to your preferences.

23.12.2. Test filtering

Starting with Gradle 1.10, it is possible to include only specific tests, based on the test name pattern. Filtering is a different mechanism than test class inclusion / exclusion that will be described in the next few paragraphs (-Dtest.single, test.include and friends). The latter is based on files, e.g. the physical location of the test implementation class. File-level test selection does not support many interesting scenarios that are possible with test-level filtering. Some of them Gradle handles now and some will be satisfied in the future releases:

  • Filtering at the level of specific test methods; executing a single test method
  • Filtering based on custom annotations (future)
  • Filtering based on test hierarchy; executing all tests that extend ceratain base class (future)
  • Filtering based on some custom runtime rule, e.g. particular value of a system property or some static state (future)

Test filtering feature has following characteristic:

  • Fully qualified class name or fully qualified method name is supported, e.g. "org.gradle.SomeTest", "org.gradle.SomeTest.someMethod"
  • Wildcard '*' is supported for matching any characters
  • Command line option "--tests" is provided to conveniently set the test filter. Especially useful for the classic 'single test method execution' use case. When the command line option is used, the inclusion filters declared in the build script are ignored.
  • Gradle tries best to filter the tests given limitations of particular test framework API. Some advanced, synthetic tests may not be fully compatible with filtering. However, vast majority of tests and use cases should be handled neatly.
  • Test filtering supersedes the file-based test selection. The latter may be completely replaced in future. We will grow the the test filtering api and add more kinds of filters.

Example 23.11. Filtering tests in the build script

build.gradle

test {
    filter {
        //include specific method in any of the tests
        includeTestsMatching "*UiCheck"

        //include all tests from package
        includeTestsMatching "org.gradle.internal.*"

        //include all integration tests
        includeTestsMatching "*IntegTest"
    }
}


For more details and examples please see the TestFilter reference.

Some examples of using the command line option:

  • gradle test --tests org.gradle.SomeTest.someSpecificFeature

  • gradle test --tests SomeTest.someSpecificFeature

  • gradle test --tests SomeSpecificTest

  • gradle test --tests all.in.specific.package*

  • gradle test --tests *IntegTest

  • gradle test --tests *IntegTest*ui*

  • gradle someTestTask --tests *UiTest someOtherTestTask --tests *WebTest*ui

23.12.3. System properties

There are two system properties that can affect test execution. Both of these are based off of the name of the test task with a suffix. If you are interested in selecting specific tests for execution make sure you read the previous paragraph on test filtering because the latter feature is more robust.

Setting a system property of taskName.single = testNamePattern will only execute tests that match the specified testNamePattern. The taskName can be a full multi-project path like ":sub1:sub2:test" or just the task name. The testNamePattern will be used to form an include pattern of "**/testNamePattern*.class". If no tests with this pattern can be found an exception is thrown. This is to shield you from false security. If tests of more then one subproject are executed, the pattern is applied to each subproject. An exception is thrown if no tests can be found for a particular subproject. In such a case you can use the path notation of the pattern, so that the pattern is applied only to the test task of a specific subproject. Alternatively you can specify the fully qualified task name to be executed. You can also specify multiple patterns. Examples:

  • gradle -Dtest.single=ThisUniquelyNamedTest test

  • gradle -Dtest.single=a/b/ test

  • gradle -DintegTest.single=*IntegrationTest integTest

  • gradle -Dtest.single=:proj1:test:Customer build

  • gradle -DintegTest.single=c/d/ :proj1:integTest

Setting a system property of taskName.debug will run the tests in debug mode, suspended and listening on port 5005. For example: gradle test -Dtest.single=ThisUniquelyNamedTest -Dtest.debug

23.12.4. Test detection

The Test task detects which classes are test classes by inspecting the compiled test classes. By default it scans all .class files. You can set custom includes / excludes, only those classes will be scanned. Depending on the test framework used (JUnit / TestNG) the test class detection uses different criteria.

When using JUnit, we scan for both JUnit 3 and 4 test classes. If any of the following criteria match, the class is considered to be a JUnit test class:

  • Class or a super class extends TestCase or GroovyTestCase

  • Class or a super class is annotated with @RunWith

  • Class or a super class contain a method annotated with @Test

When using TestNG, we scan for methods annotated with @Test.

Note that abstract classes are not executed. Gradle also scan up the inheritance tree into jar files on the test classpath.

In case you don't want to use the test class detection, you can disable it by setting scanForTestClasses to false. This will make the test task only use the includes / excludes to find test classes. If scanForTestClasses is disabled and no include or exclude patterns are specified, the respective defaults are used. For include this is "**/*Tests.class", "**/*Test.class" and the for exclude it is "**/Abstract*.class".

23.12.5. Test grouping

JUnit and TestNG allows sophisticated groupings of test methods.

For grouping JUnit test classes and methods JUnit 4.8 introduces the concept of categories. [9] The test task allows the specification of the JUnit categories you want to include and exclude.

Example 23.12. JUnit Categories

build.gradle

test {
    useJUnit {
        includeCategories 'org.gradle.junit.CategoryA'
        excludeCategories 'org.gradle.junit.CategoryB'
    }
}

The TestNG framework has a quite similar concept. In TestNG you can specify different test groups. [10] The test groups that should be included or excluded from the test execution can be configured in the test task.

Example 23.13. Grouping TestNG tests

build.gradle

test {
    useTestNG {
        excludeGroups 'integrationTests'
        includeGroups 'unitTests'
    }
}

23.12.6. Test reporting

The Test task generates the following results by default.

  • An HTML test report.

  • The results in an XML format that is compatible with the Ant JUnit report task. This format is supported by many other tools, such as CI servers.

  • Results in an efficient binary format. The task generates the other results from these binary results.

You can disable the HTML test report using the Test.setTestReport() method. The other results currently cannot be disabled.

There is also a stand-alone TestReport task type which can generate the HTML test report from the binary results generated by one or more Test task instances. To use this task type, you need to define a destinationDir and the test results to include in the report. Here is a sample which generates a combined report for the unit tests from subprojects:

Example 23.14. Creating a unit test report for subprojects

build.gradle

subprojects {
    apply plugin: 'java'

    // Disable the test report for the individual test task
    test {
        reports.html.enabled = false
    }
}

task testReport(type: TestReport) {
    destinationDir = file("$buildDir/reports/allTests")
    // Include the results from the `test` task in all subprojects
    reportOn subprojects*.test
}

You should note that the TestReport type combines the results from multiple test tasks, but it does not aggregate the results of individual test classes. This means that if a given test class is executed by multiple test tasks, then the test report will include only one execution of that class and discard the other executions of that class. This will be addressed in a future Gradle version.

23.12.6.1. TestNG parameterized methods and reporting

TestNG supports parameterizing test methods, allowing a particular test method to be executed multiple times with different inputs. Gradle includes the parameter values in its reporting of the test method execution.

Given a parameterized test method named aParameterizedTestMethod that takes two parameters, it will be reported with the name: aParameterizedTestMethod(toStringValueOfParam1, toStringValueOfParam2). This makes identifying the parameter values for a particular iteration easy.

23.12.7. Convention values

Table 23.14. Java plugin - test properties

Task Property Type Default Value
testClassesDir File sourceSets.test.output.classesDir
classpath FileCollection sourceSets.test.runtimeClasspath
testResultsDir File testResultsDir
testReportDir File testReportDir
testSrcDirs List<File> sourceSets.test.java.srcDirs

23.13. Jar

The jar task creates a JAR file containing the class files and resources of the project. The JAR file is declared as an artifact in the archives dependency configuration. This means that the JAR is available in the classpath of a dependent project. If you upload your project into a repository, this JAR is declared as part of the dependency descriptor. You can learn more about how to work with archives in Section 16.8, “Creating archives” and artifact configurations in Chapter 51, Publishing artifacts.

23.13.1. Manifest

Each jar or war object has a manifest property with a separate instance of Manifest. When the archive is generated, a corresponding MANIFEST.MF file is written into the archive.

Example 23.15. Customization of MANIFEST.MF

build.gradle

jar {
    manifest {
        attributes("Implementation-Title": "Gradle", "Implementation-Version": version)
    }
}

You can create stand alone instances of a Manifest. You can use that for example, to share manifest information between jars.

Example 23.16. Creating a manifest object.

build.gradle

ext.sharedManifest = manifest {
    attributes("Implementation-Title": "Gradle", "Implementation-Version": version)
}
task fooJar(type: Jar) {
    manifest = project.manifest {
        from sharedManifest
    }
}

You can merge other manifests into any Manifest object. The other manifests might be either described by a file path or, like in the example above, by a reference to another Manifest object.

Example 23.17. Separate MANIFEST.MF for a particular archive

build.gradle

task barJar(type: Jar) {
    manifest {
        attributes key1: 'value1'
        from sharedManifest, 'src/config/basemanifest.txt'
        from('src/config/javabasemanifest.txt', 'src/config/libbasemanifest.txt') {
            eachEntry { details ->
                if (details.baseValue != details.mergeValue) {
                    details.value = baseValue
                }
                if (details.key == 'foo') {
                    details.exclude()
                }
            }
        }
    }
}

Manifest are merged in the order they are declared by the from statement. If the based manifest and the merged manifest both define values for the same key, the merged manifest wins by default. You can fully customize the merge behavior by adding eachEntry actions in which you have access to a ManifestMergeDetails instance for each entry of the resulting manifest. The merge is not immediately triggered by the from statement. It is done lazily, either when generating the jar, or by calling writeTo or effectiveManifest

You can easily write a manifest to disk.

Example 23.18. Separate MANIFEST.MF for a particular archive

build.gradle

jar.manifest.writeTo("$buildDir/mymanifest.mf")

23.14. Uploading

How to upload your archives is described in Chapter 51, Publishing artifacts.



[9] The JUnit wiki contains a detailed description on how to work with JUnit categories: https://github.com/junit-team/junit/wiki/Categories.

[10] The TestNG documentation contains more details about test groups: http://testng.org/doc/documentation-main.html#test-groups.