Support for building Java libraries using the new software model is currently incubating. Please be aware that the DSL, APIs and other configuration may change in later Gradle versions.
The New Java plugin is intended to replace the Java plugin, and leverages the new rule based model configuration to achieve the best performance, improved expressiveness and support for variant-aware dependency management.
The plugin relies on a software model which describes how an application is built, and how components of the model relate to each other. The software model is organized around key concepts:
To use the new Java plugin, include the following in your build script:
A library is created by declaring a JvmLibrarySpec
under the components
element of the model
:
Example 70.2. Creating a source set
build.gradle
model { components { main(JvmLibrarySpec) } }
Output of gradle build
> gradle build :compileMainJarMainJava :processMainJarMainResources :createMainJar :mainJar :assemble :check UP-TO-DATE :build BUILD SUCCESSFUL
This example creates a library named main
, which will implicitly create a JavaSourceSet
named java
.
Therefore the new Java plugin follows the conventions of the legacy Java plugin, and Java sources
are expected to be found in src/main/java
,
while resources are expected to be found in src/main/resources
.
Source sets represent logical groupings of source files in a library. A library can define multiple source sets and all sources will be compiled and included in the resulting binaries. When a library is added to a build, the following source sets are added by default.
Table 70.1. Java plugin - default source sets
Source Set | Type | Directory |
java | JavaSourceSet |
src/${library.name}/java |
resources | JvmResourceSet |
src/${library.name}/resources |
It is possible to configure an existing source set
through the sources
container:
Example 70.3. Configuring a source set
build.gradle
components {
main {
sources {
java {
// configure the "java" source set
}
}
}
}
It is also possible to create an additional source set, using the
JavaSourceSet
type:
Example 70.4. Creating a new source set
build.gradle
components {
main {
sources {
mySourceSet(JavaSourceSet) {
// configure the "mySourceSet" source set
}
}
}
}
By default, when the plugins above are applied, no new tasks are added to the build. However, when libraries are defined, conventional tasks are added which build and package each binary of the library.
For each binary of a library, a single lifecycle task is created which executes all tasks associated with building the binary.
To build all binaries, the standard build
lifecycle task can be used.
Table 70.2. Java plugin - lifecycle tasks
Component Type | Binary Type | Lifecycle Task |
JvmLibrarySpec |
JvmBinarySpec |
${binary.name} |
For each source set added to a library, tasks are added to compile or process the source files for each binary.
Table 70.3. Java plugin - source set tasks
Source Set Type | Task name | Type | Description |
JavaSourceSet |
compile${binary.name}${library.name}${sourceset.name} | PlatformJavaCompile |
Compiles the sources of a given source set. |
JvmResourceSet |
process${binary.name}${library.name}${sourceset.name} | ProcessResources |
Copies the resources in the given source set to the classes output directory. |
For each binary in a library, a packaging task is added to create the jar for that binary.
Table 70.4. Java plugin - packaging tasks
Binary Type | Task name | Depends on | Type | Description |
JvmBinarySpec |
create${binary.name} | all PlatformJavaCompile and ProcessResources
tasks associated with the binary |
Jar |
Packages the compiled classes and processed resources of the binary. |
Gradle provides a report that you can run from the command-line that shows details about the components and binaries that your
project produces. To use this report, just run gradle components
. Below is an example of running this report for
one of the sample projects:
Example 70.5. The components report
Output of gradle components
> gradle components :components ------------------------------------------------------------ Root project ------------------------------------------------------------ JVM library 'main' ------------------ Source sets Java source 'main:java' srcDir: src/main/java Java source 'main:mySourceSet' srcDir: src/main/mySourceSet JVM resources 'main:resources' srcDir: src/main/resources Binaries Jar 'mainJar' build using task: :mainJar platform: java7 tool chain: JDK 7 (1.7) Jar file: build/jars/mainJar/main.jar Note: currently not all plugins register their components, so some components may not be visible here. BUILD SUCCESSFUL Total time: 1 secs
The new Java plugin supports API dependencies between components. Having an API dependency means that if
A
depends on B
, then the API of B
is required to compile A
. Gradle will then
make sure that the dependency is built before the dependent component, and that the dependency
appears on the compile classpath.
API dependencies are (by nature) not transitive. Runtime (transitive) dependency management is not implemented yet.
Currently the plugin supports two kinds of dependencies:
Dependencies onto external components are not yet supported.
Dependencies are declared on a SourceSet
:
Example 70.6. Declaring a dependency onto a library
build.gradle
model {
components {
core(JvmLibrarySpec)
server(JvmLibrarySpec) {
sources {
java {
dependencies {
library 'core'
}
}
}
}
}
}
Output of gradle serverJar
> gradle serverJar :compileCoreJarCoreJava :processCoreJarCoreResources :createCoreJar :coreJar :compileServerJarServerJava :createServerJar :serverJar BUILD SUCCESSFUL
This example declares an API dependency for the java
source set of the server
library
onto the core
library of the same project. However, it is possible for a library to depend on a library in a different
project as well:
Example 70.7. Declaring a dependency onto a project with an explicit library
build.gradle
client(JvmLibrarySpec) { sources { java { dependencies { project ':util' library 'main' } } } }
Output of gradle clientJar
> gradle clientJar :util:compileMainJarMainJava :util:createMainJar :util:mainJar :compileClientJarClientJava :createClientJar :clientJar BUILD SUCCESSFUL
When the target project only defines a single library, the library
selector can be omitted
altogether:
Example 70.8. Declaring a dependency onto a project with an implicit library
build.gradle
dependencies {
project ':util'
}
The DependencySpecContainer
class provides a complete reference of the dependencies DSL.
The software model extracts the target platform as a core concept. In the Java world, this means that a library can be built, or resolved, against a specific version of Java. For example, if you compile a library for Java 5, we know that such a library can be consumed by a library built for Java 6, but the opposite is not true. Gradle lets you define which platforms a library targets, and will take care of:
The targetPlatform
DSL defines which platforms a library should be built against:
Example 70.9. Declaring target platforms
core/build.gradle
model { components { main(JvmLibrarySpec) { targetPlatform 'java5' targetPlatform 'java6' } } }
Output of gradle :core:build
> gradle :core:build :core:compileJava5MainJarMainJava :core:processJava5MainJarMainResources :core:createJava5MainJar :core:java5MainJar :core:compileJava6MainJarMainJava :core:compileJava6MainJarMainJava6 :core:processJava6MainJarMainResources :core:createJava6MainJar :core:java6MainJar :core:assemble :core:check UP-TO-DATE :core:build BUILD SUCCESSFUL
When building the application, Gradle generates two binaries: java5MainJar
and java6MainJar
corresponding to the target versions of Java. These artifacts will participate in dependency resolution as described
here.
For each JvmLibrarySpec
it is possible to define additional source sets for each binary. A common use case for this
is having specific dependencies for each variant and source sets that conform to those dependencies. The example below configures a java6
source set on the java6MainJar
binary:
Example 70.10. Declaring binary specific sources
core/build.gradle
main { binaries.named('java6MainJar') { sources { java6(JavaSourceSet) { source.srcDir 'src/main/java6' } } } }
Output of gradle :core:java6MainJar
> gradle :core:java6MainJar :core:compileJava6MainJarMainJava UP-TO-DATE :core:compileJava6MainJarMainJava6 UP-TO-DATE :core:processJava6MainJarMainResources UP-TO-DATE :core:createJava6MainJar UP-TO-DATE :core:java6MainJar UP-TO-DATE BUILD SUCCESSFUL
When a library targets multiple versions of Java and depends on another library, Gradle will make its best effort to resolve the dependency to the most appropriate version of the dependency library. In practice, this means that Gradle chooses the highest compatible version:
B
built for Java n
D
built for Java m
D
is compatible with B
if m<=n
D(java 5), D(java 6), ...D(java m)
, choose the compatible D binary with the highest Java version
Example 70.11. Declaring target platforms
server/build.gradle
model { components { main(JvmLibrarySpec) { targetPlatform 'java5' targetPlatform 'java6' sources { java { dependencies { project ':core' library 'main' } } } } } }
Output of gradle :server:build
> gradle :server:build :core:compileJava5MainJarMainJava UP-TO-DATE :core:processJava5MainJarMainResources UP-TO-DATE :core:createJava5MainJar UP-TO-DATE :core:java5MainJar UP-TO-DATE :server:compileJava5MainJarMainJava :server:createJava5MainJar :server:java5MainJar :core:compileJava6MainJarMainJava UP-TO-DATE :core:compileJava6MainJarMainJava6 UP-TO-DATE :core:processJava6MainJarMainResources UP-TO-DATE :core:createJava6MainJar UP-TO-DATE :core:java6MainJar UP-TO-DATE :server:compileJava6MainJarMainJava :server:createJava6MainJar :server:java6MainJar :server:assemble :server:check UP-TO-DATE :server:build BUILD SUCCESSFUL
In the example above, Gradle automatically chooses the Java 6 variant of the dependency for the Java 6 variant of the server
component,
and chooses the Java 5 version of the dependency for the Java 5 variant of the server
component.
The Java plugin, in addition to the target platform resolution, supports resolution of custom variants. Custom variants
can be defined on custom binary types, as long as they extends JarBinarySpec
. Users interested
in testing this incubating feature can check out the documentation of the Variant
annotation.