In the previous articles, we learned the basics of Gradle build tasks. It is recommended to read the earlier articles:
- Introduction to Gradle Series
- Gradle and Groovy Basics
- Gradle Series: Basics of Build Scripts
- Gradle Series: Gradle Tasks
- Gradle Series: Gradle Plugins
In the previous article, we learned about Gradle plugins and how to customize a Gradle plugin. This article mainly focuses on Java Gradle plugin-related knowledge, as the content related to the Java Gradle plugin is also the foundation for the Android Gradle plugin. Using Gradle to build projects is essentially about helping developers perform repetitive tasks, such as configuring third-party dependencies, compiling source files, unit testing, packaging, and publishing. Using the corresponding Gradle plugins can facilitate project building and improve development efficiency to a certain extent. The main content we will learn today includes:
- Using the Java Gradle Plugin
- Project Structure Conventions for Java Plugin
- Configuring Third-Party Dependencies
- How to Build a Java Project
- Concept of SourceSet
- Tasks that can be added by the Java Plugin
- Properties that can be added by the Java Plugin
- Multi-Project Builds
- Publishing Artifacts
Using the Java Gradle Plugin#
To use a Gradle plugin, the Project's apply() method is used:
// java is the plugin id for the Java Gradle plugin
apply plugin: 'java'
After using the Java plugin, default settings and conventions will be added to the current project, such as the location of source code, unit test code, resource files, etc. Generally, the default settings can be used.
Project Structure Conventions for Java Plugin#
The Java plugin sets some default settings and conventions. Let's take a look at the default project directory for a Java project, which is generally structured as follows:
JavaGradle
└─src
├─main
│ ├─java
│ └─resources
└─test
├─java
└─resources
In the above directory structure, src/main/java
is the default directory for source code, src/main/resources
is the directory for resource files and configuration files, and the directories under src/test
are, of course, for storing files related to unit tests. main
and test
are the two built-in source sets in the Java Gradle plugin. Besides these, you can define other source sets as follows:
apply plugin: 'java'
sourceSets {
// Specify a new source set
vip {
}
}
Then create the corresponding java
and resources
directories under src
, with the contents of the files in these directories being similar to the defaults. The default directory structure is as follows:
// Source code directory
src/vip/java
// Resource files directory
src/vip/resource
The above directory structure is the default implementation of the Java Gradle plugin. You can also modify the specific directory locations, configured as follows:
sourceSets {
// Modify the default directories; the following are still the same as the default locations, modify as needed
main {
java {
srcDir 'src/java'
}
resources {
srcDir 'src/resources'
}
}
}
Configuring Third-Party Dependencies#
During development, third-party jar packages are often used, and at this point, dependency configuration for the jar packages is necessary. The types of repositories and their locations need to be specified. When configuring dependencies, Gradle will look for the relevant dependencies in the specified repositories. The configuration for repositories and specific dependencies is as follows:
// Configure repository locations
repositories {
// Repository types such as jcenter, ivy, maven central, maven local, maven private server, etc.
mavenCentral()
mavenLocal()
maven {
uri "http" //xxxx
}
jcenter()
google()
//...
}
// Configure specific dependencies
dependencies {
// Three elements of a dependency: group, name, version
// Corresponding to Maven's GAV (groupId, artifactId, version)
// Full syntax
compile group: 'com.squareup.okhttp3', name: 'okhttp', version: '3.0.1'
// Short syntax
compile 'com.squareup.okhttp3:okhttp:3.0.1'
}
In the above code, compile
is a compile-time dependency. Gradle also provides other dependency types, as follows:
compile: Compile-time dependency
runtime: Runtime dependency
testCompile: Compile-time dependency for testing
testRuntime: Dependency only during test case execution
archives: Dependency for publishing artifacts, such as jar packages
default: Default dependency configuration
After Gradle 3.0, implementation
and api
will replace compile
. We won't elaborate on these two dependency types here, as learning the new API is not the focus of this article. The Java Gradle plugin also supports specifying different dependencies for different source sets, as follows:
// Configure different dependencies for different source sets
dependencies {
// Configuration format: sourceSetCompile, sourceSetRuntime
mainCompile 'com.squareup.okhttp3:okhttp:3.0.1'
vipCompile 'com.squareup.okhttp3:okhttp:2.0.1'
}
The above describes the dependency on an external library. Additionally, during development, you may encounter module dependencies and file dependencies. In fact, module dependencies refer to dependencies on a subproject, while file dependencies generally refer to jar package dependencies.
In the article on the basics of build scripts in the Gradle series, it has been established that to build a subproject, the include
keyword must be used in the settings.gradle
file to include the subproject. The same applies here; now the projects to be depended upon must be included in the settings.gradle
file, and then a specific subproject can be depended upon as follows:
// Depend on a subproject
dependencies {
// Include ':childProject' in the settings.gradle file
// Depend on the subproject
compile project('childProject')
}
File dependencies mainly refer to jar package dependencies. Generally, jar packages are placed in the project's libs
directory, and then the jar packages are referenced, as follows:
// Depend on a jar package
dependencies {
// Configure a single jar
compile file('libs/java1.jar')
// Configure multiple jars
compile files('libs/java1.jar', 'libs/java2.jar')
// Batch configure jars; by configuring the path where the jars are located, all files with the jar suffix will be included in the project
compile fileTree(dir: 'libs', include: '*.jar')
}
How to Build a Java Project#
All operations in Gradle are based on tasks, and the Java Gradle plugin also comes with a series of tasks to help us build projects. Executing the build
task will start building the current project. You can use gradlew build
to begin executing the build task. Gradle will compile source code files, process resource files, generate jar packages, compile test code, run unit tests, etc.
For example, in Android development, there is a clean
task. Executing the clean operation will delete the build
folder and other files generated during the project build. If there is a compilation error, you can try to clean and then build again. Additionally, there is a check
task, which will be used during unit testing. The javadoc
task can conveniently generate Java-formatted API documentation. Learning how to build a Java project is still for preparing to learn about building Android projects, so this concludes how to use Gradle to build a Java project.
Concept of SourceSet#
In this section, we will get to know SourceSet, which is the source set mentioned earlier. It is an abstract concept used by the Java Gradle plugin to describe and manage source code and its resources. It is a collection of Java source files and resource files, allowing you to configure the location of source files and set properties for the source set. Source sets can group and manage source code based on different business needs, such as the main
and test
source directories provided by the Java Gradle plugin by default, one for business code and the other for unit tests, which is very convenient.
The Java Gradle plugin provides a sourceSet
property and a sourceSet{}
closure under the Project to access and configure source sets. sourceSet
is a SourceSetContainer
, and the common properties of source sets are as follows:
// For example, main, test, etc. represent the names of source sets
name(String)
// Represents the directory for class files generated after compilation
output.classDir(File)
// Represents the directory for resource files generated after compilation
output.resourcesDir(File)
// Represents the classpath required for the source set after compilation
compileClasspath(FileCollection)
// Represents the Java source files for the source set
java(SourceDirectorySet)
// Represents the directory where the Java source files for the source set are located
java.srcDirs(Set)
// Represents the resource files for the source set
resources(SourceDirectorySet)
// Represents the directory where the resource files for the source set are located
resources.srcDirs(Set)
Below is how to set the output directory for the main
source set:
// Set properties for a specific source set
sourceSets {
main {
// Source set name is read-only
println name
// Other property settings
// From 4.0 onwards, this has been deprecated. The replacement is dir
output.classesDir = file("a/b")
// output.dir("a/b")
output.resourcesDir = file("a/b")
//....
}
}
Tasks that can be added by the Java Plugin#
The project build is still carried out through a series of tasks provided by Gradle plugins. Below are commonly used tasks in Java projects:
Task Name | Type | Description |
---|---|---|
Default source set common tasks | ||
compileJava | JavaCompile | Indicates using javac to compile Java source files |
processResources | Copy | Indicates copying resource files to the generated resource file directory |
classes | Task | Indicates assembling the generated class and resource file directory |
compileTestJava | JavaCompile | Indicates using javac to compile test Java source files |
processTestResources | Copy | Indicates copying resource files to the generated resource file directory |
testClasses | Task | Indicates assembling the generated test classes and related resource files |
jar | Jar | Indicates assembling a jar file |
javadoc | Javadoc | Indicates using javadoc to generate Java API documentation |
uploadArchives | Upload | Indicates uploading the build containing the Jar, configured using the archives{} closure |
clean | Delete | Indicates cleaning the generated directory files from the build |
cleanTaskName | Delete | Indicates deleting files generated by a specific task, such as cleanJar which deletes files generated by the jar task |
Custom source set tasks | (SourceSet is the specific source set name) | |
compileSourceSetJava | JavaCompile | Indicates using javac to compile the source code of the specified source set |
processSourceSetResources | Copy | Indicates copying the resource files of the specified source set to the resource directory in the generated files |
sourcesSetClasses | Task | Indicates assembling the classes and resource file directory for the given source set |
Properties that can be added by the Java Plugin#
Common properties in the Java Gradle plugin are added to the Project, and these properties can be used directly, as follows:
Property Name | Type | Description |
---|---|---|
sourceSets | SourceSetContainer | The source sets of the Java project, which can be configured within the closure |
sourceCompatibility | JavaVersion | The Java version used to compile Java source files |
targetCompatibility | JavaVersion | The Java version for the generated classes |
archivesBaseName | String | The name of the jar or zip file to be packaged |
manifest | Manifest | Used to access and configure the manifest file |
libsDir | File | The directory for storing generated libraries |
distsDir | File | The directory for storing generated release files |
Multi-Project Builds#
Using Gradle for multi-project builds generally involves a main project depending on other submodule projects. Whether to build these subprojects is mainly configured in the settings.gradle
file. To use these subprojects, project dependencies must be configured in the main project. The three types of dependencies mentioned earlier are library dependencies, project dependencies, and file dependencies. Here, project dependencies are used, and subprojects
and allprojects
are frequently used in multi-project configurations, as follows:
// Unified configuration for subprojects
subprojects {
// Configure all subprojects to use the Java Gradle plugin
apply plugin: 'java'
// Configure all subprojects to use the Maven central repository
repositories {
mavenCentral()
}
// Other common configurations
//...
}
// Unified configuration for all projects
allprojects {
// Configure all projects to use the Java Gradle plugin
apply plugin: 'java'
// Configure all projects to use the Maven central repository
repositories {
mavenCentral()
}
// Other common configurations
//...
}
Publishing Artifacts#
The products of Gradle builds are generally referred to as artifacts. A build can be a jar package, zip package, etc. So how do we publish artifacts? Below is how to publish a jar artifact to the local project folder or mavenLocal()
, as follows:
/**
* Publish artifacts to the project folder or mavenLocal()
*/
apply plugin: 'java'
// Task to generate jar, similar to custom wrapper
task publishJar(type: Jar)
// Artifact version
version '1.0.0'
// Artifact configuration through artifacts{} closure
artifacts {
archives publishJar
}
// Artifact publishing upload
uploadArchives {
repositories {
flatDir {
name 'libs'
dirs "$projectDir/libs"
}
// Publish the build to mavenLocal()
mavenLocal()
}
}
Executing the uploadArchives
task will generate the corresponding jar file in the appropriate location. The command is as follows:
// Execute uploadArchives
gradle uploadArchives
After successful execution, you will see the generated jar file in the project's libs
directory, as shown in the following image:
After successful execution, you will also see the generated jar file in the user's .m2/repository
directory, as shown in the following image:
Below is how to publish the jar to a built maven private server, with the code as follows:
/**
* Publish artifacts to a maven private server
*/
apply plugin: 'java'
apply plugin: 'maven'
// Task to generate jar, similar to custom wrapper
task publishJar(type: Jar)
// Artifact version
version '1.0.0'
// Artifact configuration through artifacts{} closure
artifacts {
archives publishJar
}
// Artifact publishing upload
uploadArchives {
repositories {
mavenDeployer {
repository(url: 'http://xxx') {
// Repository username and password
authentication(userName: 'username', password: 'pass')
}
snapshotRepository(url: 'http://xxx') {
authentication(userName: 'username', password: 'pass')
}
}
}
}
The upload process also involves executing the uploadArchives
task. If you have a maven private server, you can give it a try. This concludes the study of the Java Gradle plugin, and the next article will officially begin the study of the Android Gradle plugin.