Table of Contents
The Java plugin adds Java compilation along with testing and bundling capabilities to a project. It serves as the basis for many of the other JVM language Gradle plugins. You can find a comprehensive introduction and overview to the Java Plugin in the Building Java & JVM projects chapter.
To use the Java plugin, include the following in your build script:
The Java plugin assumes the project layout shown below. None of these directories need to exist or have anything in them. The Java plugin will compile whatever it finds, and handles anything which is missing.
src/main/javaProduction Java source.
src/main/resourcesProduction resources, such as XML and properties files.
src/test/javaTest Java source.
src/test/resourcesTest resources.
src/sourceSet/javaJava source for the source set named sourceSet.
src/sourceSet/resourcesResources for the source set named sourceSet.
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: Custom Java source layout
build.gradle
sourceSets {
main {
java {
srcDirs = ['src/java']
}
resources {
srcDirs = ['src/resources']
}
}
}
The plugin adds the following source sets:
mainContains the production source code of the project, which is compiled and assembled into a JAR.
testContains your test source code, which is compiled and executed using JUnit or TestNG. These are typically unit tests, but you can include any test in this source set as long as they all share the same compilation and runtime classpaths.
The following table lists some of the important properties of a source set. You can find more details in the API documentation for SourceSet.
name— (read-only)StringThe name of the source set, used to identify it.
output— (read-only)SourceSetOutputThe output files of the source set, containing its compiled classes and resources.
output.classesDirs— (read-only)FileCollectionDefault value:
$buildDir/classes/java/$name, e.g. build/classes/java/mainThe directories to generate the classes of this source set into. May contain directories for other JVM languages, e.g. build/classes/kotlin/main.
output.resourcesDir—FileDefault value:
$buildDir/resources/$name, e.g. build/resources/mainThe directory to generate the resources of this source set into.
compileClasspath—FileCollectionDefault value:
${name}CompileClasspathconfigurationThe classpath to use when compiling the source files of this source set.
annotationProcessorPath—FileCollectionDefault value:
${name}AnnotationProcessorconfigurationThe processor path to use when compiling the source files of this source set.
runtimeClasspath—FileCollectionDefault value:
$output,${name}RuntimeClasspathconfigurationThe classpath to use when executing the classes of this source set.
java— (read-only)SourceDirectorySetThe Java source files of this source set. Contains only
.javafiles found in the Java source directories, and excludes all other files.java.srcDirs—Set<File>Default value:
src/$name/java, e.g. src/main/javaThe source directories containing the Java source files of this source set. You can set this to any value that is described in this section.
java.outputDir—FileDefault value:
$buildDir/classes/java/$name, e.g. build/classes/java/mainThe directory to generate compiled Java sources into. You can set this to any value that is described in this section.
resources— (read-only)SourceDirectorySetThe resources of this source set. Contains only resources, and excludes any
.javafiles found in the resource directories. Other plugins, such as the Groovy Plugin, exclude additional types of files from this collection.resources.srcDirs—Set<File>Default value:
[src/$name/resources]The directories containing the resources of this source set. You can set this to any type of value that is described in this section.
allJava— (read-only)SourceDirectorySetDefault value: Same as
javapropertyAll Java files of this source set. Some plugins, such as the Groovy Plugin, add additional Java source files to this collection.
allSource— (read-only)SourceDirectorySetDefault value: Sum of everything in the
resourcesandjavapropertiesAll source files of this source set of any language. This includes all resource files and all Java source files. Some plugins, such as the Groovy Plugin, add additional source files to this collection.
See the integration test example in the Testing in Java & JVM projects chapter.
Adding a JAR containing the classes of a source set:
Example: Assembling a JAR for a source set
build.gradle
task intTestJar(type: Jar) {
from sourceSets.intTest.output
}
Generating Javadoc for a source set:
Example: 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: Running tests in a source set
build.gradle
task intTest(type: Test) {
testClassesDirs = sourceSets.intTest.output.classesDirs
classpath = sourceSets.intTest.runtimeClasspath
}
The Java plugin adds a number of tasks to your project, as shown below.
compileJava— type:JavaCompileDepends on: All tasks which contribute to the compilation classpath, including
jartasks from projects that are on the classpath via project dependenciesCompiles production Java source files using the JDK compiler.
processResources— type:CopyCopies production resources into the production resources directory.
classesDepends on:
compileJava,processResourcesThis is an aggregate task that just depends on other tasks. Other plugins may attach additional compilation tasks to it.
compileTestJava— type:JavaCompileDepends on:
classes, and all tasks that contribute to the test compilation classpathCompiles test Java source files using the JDK compiler.
processTestResources— type:CopyCopies test resources into the test resources directory.
testClassesDepends on:
compileTestJava,processTestResourcesThis is an aggregate task that just depends on other tasks. Other plugins may attach additional test compilation tasks to it.
jar— type:JarDepends on:
classesAssembles the production JAR file, based on the classes and resources attached to the
mainsource set.javadoc— type:JavadocDepends on:
classesGenerates API documentation for the production Java source using Javadoc.
test— type:TestDepends on:
testClasses, and all tasks which produce the test runtime classpathRuns the unit tests using JUnit or TestNG.
uploadArchives— type:UploadDepends on:
jar, and any other task that produces an artifact attached to thearchivesconfigurationUploads artifacts in the
archivesconfiguration — including the production JAR file — to the configured repositories.clean— type:DeleteDeletes the project build directory.
cleanTaskName— type:DeleteDeletes files created by the specified task. For example,
cleanJarwill delete the JAR file created by thejartask andcleanTestwill delete the test results created by thetesttask.
For each source set you add to the project, the Java plugin adds the following tasks:
compileSourceSetJava— type:JavaCompileDepends on: All tasks which contribute to the source set’s compilation classpath
Compiles the given source set’s Java source files using the JDK compiler.
processSourceSetResources— type:CopyCopies the given source set’s resources into the resources directory.
sourceSetClasses— type:TaskDepends on:
compileSourceSetJava,processSourceSetResourcesPrepares the given source set’s classes and resources for packaging and execution. Some plugins may add additional compilation tasks for the source set.
The Java plugin attaches some of its tasks to the lifecycle tasks defined by the Base Plugin — which the Java Plugin applies automatically — and it also adds a few other lifecycle tasks:
assembleDepends on:
jar, and all other tasks that create artifacts attached to thearchivesconfigurationAggregate task that assembles all the archives in the project. This task is added by the Base Plugin.
checkDepends on:
testAggregate task that performs verification tasks, such as running the tests. Some plugins add their own verification tasks to
check. You should also attach any customTesttasks to this lifecycle task if you want them to execute for a full build. This task is added by the Base Plugin.buildDepends on:
check,assembleAggregate tasks that performs a full build of the project. This task is added by the Base Plugin.
buildNeededDepends on:
build, andbuildNeededtasks in all projects that are dependencies in thetestRuntimeClasspathconfiguration.Performs a full build of the project and all projects it depends on.
buildDependentsDepends on:
build, andbuildDependentstasks in all projects that have this project as a dependency in theeirtestRuntimeClasspathconfigurationsPerforms a full build of the project and all projects which depend upon it.
buildConfigName— task ruleDepends on: all tasks that generate the artifacts attached to the named — ConfigName — configuration
Assembles the artifacts for the specified configuration. This rule is added by the Base Plugin.
uploadConfigName— task rule, type:UploadDepends on: all tasks that generate the artifacts attached to the named — ConfigName — configuration
Assembles and uploads the artifacts in the specified configuration. This rule is added by the Base Plugin.
The following diagram shows the relationships between these tasks.
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.
To find information on the api configuration, please consult the Java Library Plugin reference documentation and the Dependency Management Tutorial.
compile(Deprecated)Compile time dependencies. Superseded by
implementation.implementationextendscompileImplementation only dependencies.
compileOnlyCompile time only dependencies, not used at runtime.
compileClasspathextendscompile, compileOnly, implementationCompile classpath, used when compiling source. Used by task
compileJava.annotationProcessorAnnotation processors used during compilation.
runtime(Deprecated) extendscompileRuntime dependencies. Superseded by
runtimeOnly.runtimeOnlyRuntime only dependencies.
runtimeClasspathextendsruntimeOnly, runtime, implementationRuntime classpath contains elements of the implementation, as well as runtime only elements.
testCompile(Deprecated) extendscompileAdditional dependencies for compiling tests. Superseded by
testImplementation.testImplementationextendstestCompile, implementationImplementation only dependencies for tests.
testCompileOnlyAdditional dependencies only for compiling tests, not used at runtime.
testCompileClasspathextendstestCompile, testCompileOnly, testImplementationTest compile classpath, used when compiling test sources. Used by task
compileTestJava.testRuntime(Deprecated) extendsruntime, testCompileAdditional dependencies for running tests only. Used by task
test. Superseded bytestRuntimeOnly.testRuntimeOnlyextendsruntimeOnlyRuntime only dependencies for running tests. Used by task
test.testRuntimeClasspathextendstestRuntimeOnly, testRuntime, testImplementationRuntime classpath for running tests.
archivesArtifacts (e.g. jars) produced by this project. Used by tasks
uploadArchives.defaultextendsruntimeThe default configuration used by a project dependency on this project. Contains the artifacts and dependencies required by this project at runtime.
For each source set you add to the project, the Java plugins adds the following dependency configurations:
sourceSetCompile(Deprecated)Compile time dependencies for the given source set. Superseded by
sourceSetImplementation.sourceSetImplementationextendssourceSetCompileCompile time dependencies for the given source set. Used by
sourceSetCompileClasspath, sourceSetRuntimeClasspath.sourceSetCompileOnlyCompile time only dependencies for the given source set, not used at runtime.
sourceSetCompileClasspathextendscompileSourceSetJavaCompile classpath, used when compiling source. Used by
sourceSetCompile, sourceSetCompileOnly, sourceSetImplementation.sourceSetAnnotationProcessorAnnotation processors used during compilation of this source set.
sourceSetRuntime(Deprecated)Runtime dependencies for the given source set. Used by
sourceSetCompile. Superseded bysourceSetRuntimeOnly.sourceSetRuntimeOnlyRuntime only dependencies for the given source set.
sourceSetRuntimeClasspathextendssourceSetRuntimeOnly, sourceSetRuntime, sourceSetImplementationRuntime classpath contains elements of the implementation, as well as runtime only elements.
components.javaA
SoftwareComponentfor publishing the production JAR created by thejartask. This component includes the runtime dependency information for the JAR.
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.
String reporting.baseDirThe name of the directory to generate reports into, relative to the build directory. Default value:
reports(read-only) File reportsDirThe directory to generate reports into. Default value:
buildDir/reporting.baseDirString testResultsDirNameThe name of the directory to generate test result .xml files into, relative to the build directory. Default value:
test-results(read-only) File testResultsDirThe directory to generate test result .xml files into. Default value:
buildDir/testResultsDirNameString testReportDirNameThe name of the directory to generate the test report into, relative to the reports directory. Default value:
tests(read-only) File testReportDirThe directory to generate the test report into. Default value:
reportsDir/testReportDirNameString libsDirNameThe name of the directory to generate libraries into, relative to the build directory. Default value:
libs(read-only) File libsDirThe directory to generate libraries into. Default value:
buildDir/libsDirNameString distsDirNameThe name of the directory to generate distributions into, relative to the build directory. Default value:
distributions(read-only) File distsDirThe directory to generate distributions into. Default value:
buildDir/distsDirNameString docsDirNameThe name of the directory to generate documentation into, relative to the build directory. Default value:
docs(read-only) File docsDirThe directory to generate documentation into. Default value:
buildDir/docsDirNameString dependencyCacheDirNameThe name of the directory to use to cache source dependency information, relative to the build directory. Default value:
dependency-cache
(read-only)SourceSetContainersourceSetsContains the project’s source sets. Default value: Not null
SourceSetContainerJavaVersionsourceCompatibilityJava version compatibility to use when compiling Java source. Default value: version of the current JVM in use
JavaVersion. Can also set using a String or a Number, e.g.'1.5'or1.5.JavaVersiontargetCompatibilityJava version to generate classes for. Default value:
sourceCompatibility. Can also set using a String or Number, e.g.'1.5'or1.5.String archivesBaseNameThe basename to use for archives, such as JAR or ZIP files. Default value:
projectNameManifestmanifestThe manifest to include in all JAR files. Default value: an empty manifest.
These properties are provided by convention objects of type JavaPluginConvention, and BasePluginConvention.
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.
FileCollectionclasspathDefault value:
sourceSets.main.output+sourceSets.main.compileClasspathFileTreesourceDefault value:
sourceSets.main.allJava. Can set using anything described in the section called “Understanding implicit conversion to file collections”.File destinationDirDefault value:
docsDir/javadocString titleDefault value: The name and version of the project
The clean task is an instance of Delete. It simply removes the directory denoted by its dir property.
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 the section called “File copying in depth”.
Object srcDirsDefault value:
sourceSet.resources. Can set using anything described in the section called “Understanding implicit conversion to file collections”.File destinationDirDefault value:
sourceSet.output.resourcesDir. Can set using anything described in the section called “File paths in depth”.
The Java plugin adds a JavaCompile instance for each source set in the project. Some of the most common configuration options are shown below.
FileCollectionclasspathDefault value:
sourceSet.compileClasspathFileTreesourceDefault value:
sourceSet.java. Can set using anything described in the section called “Understanding implicit conversion to file collections”.File destinationDirDefault value:
sourceSet.java.outputDir
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.
Starting with Gradle 2.1, it is possible to compile Java incrementally. See the JavaCompile task for information on how to enable it.
The main goals for incremental compilation are:
Make incremental builds much faster.
Change as few output classes as possible. Classes that don’t need to be recompiled remain unchanged in the output directory. An example scenario when this is really useful is using JRebel - the fewer output classes are changed the quicker the JVM can use refreshed classes.
To help you understand how incremental compilation works, the following provides a high-level overview:
Gradle will recompile all classes affected by a change.
A class is affected if it has been changed or if it depends on another affected class. This works no matter if the other class is defined in the same project, another project or even an external library.
A class’s dependencies are determined from type references in its bytecode.
Since constants can be inlined, any change to a constant will result in Gradle recompiling all source files. For that reason, you should try to minimize the use of constants in your source code and replace them with static methods where possible.
Since source-retention annotations are not visible in bytecode, changes to a source-retention annotation will result in full recompilation.
You can improve incremental compilation performance by applying good software desing principles like loose coupling. For instance, if you put an interface between a concrete class and its dependents, the dependent classes are only recompiled when the interface changes, but not when the implementation changes.
The class analysis is cached in the project directory, so the first build after a clean checkout can be slower. Consider turning off the incremental compiler on your build server.
Starting with Gradle 4.7, the incremental compiler also supports incremental annotation processing. Annotation processors need to opt in to this feature, otherwise they will trigger a full recompilation.
As a user you can see which annotation processors are triggering full recompilations in the --info log.
Incremental annotation processing will be deactivated if a custom executable or javaHome is configured on the compile task.
Please first have a look at the section called “Incremental Java compilation”, as incremental annotation processing builds on top of it.
Gradle supports incremental compilation for two common categories of annotation processors: "isolating" and "aggregating". Please consult the information below to decide which category fits your processor.
You can then register your processor for incremental compilation using a file in the processor’s META-INF directory. The format is one line per processor, with the fully qualified name of the processor class and its category separated by a comma.
Example: Registering incremental annotation processors
processor/src/main/resources/META-INF/gradle/incremental.annotation.processors
EntityProcessor,isolating ServiceRegistryProcessor,dynamic
If your processor can only decide at runtime whether it is incremental or not, you can declare it as "dynamic" in the META-INF descriptor and return its true type at runtime using the Processor#getSupportedOptions() method.
Example: Registering incremental annotation processors dynamically
processor/src/main/java/ServiceRegistryProcessor.java
@Override public Set<String> getSupportedOptions() { return Collections.singleton("org.gradle.annotation.processing.aggregating"); }
Both categories have the following limitations:
They must generate their files using the Filer API. Writing files any other way will result in silent failures later on, as these files won’t be cleaned up correctly. If your processor does this, it cannot be incremental.
They must not depend on compiler-specific APIs like com.sun.source.util.Trees. Gradle wraps the processing APIs, so attempts to cast to compiler-specific types will fail. If your processor does this, it cannot be incremental, unless you have some fallback mechanism.
If they use Filer#getResource, Gradle will recompile all source files. See gradle/issues/4701
If they use Filer#createResource, Gradle will recompile all source files. See gradle/issues/4702
The fastest category, these look at each annotated element in isolation, creating generated files or validation messages for it.
For instance an EntityProcessor could create a <TypeName>Repository for each type annotated with @Entity.
Example: An isolated annotation processor
processor/src/main/java/EntityProcessor.java
Set<? extends Element> entities = roundEnv.getElementsAnnotatedWith(entityAnnotation); for (Element entity : entities) { createRepository((TypeElement) entity); }
"Isolating" processors have the following limitations:
They must make all decisions (code generation, validation messages) for an annotated type based on information reachable from its AST. This means you can analyze the types' super-class, method return types, annotations etc., even transitively. But you cannot make decisions based on unrelated elements in the RoundEnvironment. Doing so will result in silent failures because too few files will be recompiled later. If your processor needs to make decisions based on a combination of otherwise unrelated elements, mark it as "aggregating" instead.
They must provide exactly one originating element for each file generated with the
FilerAPI. If zero or many originating elements are provided, Gradle will recompile all source files.
When a source file is recompiled, Gradle will recompile all files generated from it. When a source file is deleted, the files generated from it are deleted.
These can aggregate several source files into one ore more output files or validation messages.
For instance, a ServiceRegistryProcessor could create a single ServiceRegistry with one method for each type annotated with @Service
Example: An aggregating annotation processor
processor/src/main/java/ServiceRegistryProcessor.java
JavaFileObject serviceRegistry = filer.createSourceFile("ServiceRegistry"); Writer writer = serviceRegistry.openWriter(); writer.write("public class ServiceRegistry {"); for (Element service : roundEnv.getElementsAnnotatedWith(serviceAnnotation)) { addServiceCreationMethod(writer, (TypeElement) service); } writer.write("}"); writer.close();
"Aggregating" processors have the following limitations:
They can only read
CLASSorRUNTIMEretention annotationsThey can only read parameter names if the user passes the
-parameterscompiler argument.
Gradle will always reprocess (but not recompile) all annotated files that the processor was registered for. Gradle will always recompile any files the processor generates.
If a dependent project has changed in an ABI-compatible way (only its private API has changed), then Java compilation tasks will be up-to-date. This means that if project A depends on project B and a class in B is changed in an ABI-compatible way (typically, changing only the body of a method), then Gradle won’t recompile A.
Some of the types of changes that do not affect the public API and are ignored:
Changing a method body
Changing a comment
Adding, removing or changing private methods, fields, or inner classes
Adding, removing or changing a resource
Changing the name of jars or directories in the classpath
Renaming a parameter
Compile-avoidance is deactivated if annotation processors are found on the compile classpath, because for annotation processors the implementation details matter. Annotation processors should be declared on the annotation processor path instead. Gradle 5.0 will ignore processors on the compile classpath.
Example: Declaring annotation processors
build.gradle
dependencies {
// The dagger compiler and its transitive dependencies will only be found on annotation processing classpath
annotationProcessor 'com.google.dagger:dagger-compiler:2.8'
// And we still need the Dagger library on the compile classpath itself
implementation 'com.google.dagger:dagger:2.8'
}
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.
See the Testing in Java & JVM projects chapter for more details.
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 the section called “Archive creation in depth” and artifact configurations in Legacy publishing.
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: 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: 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: 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()
}
}
}
}
}
Manifests are merged in the order they are declared by the from statement. If the base 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.

