The Java plugin provides a lot of useful tasks and properties that we can use for building a Java application or library. If we follow the convention-over-configuration support of the plugin, we don't have to write a lot of code in our Gradle build file to use it. If we want to, we can still add extra configuration options to override the default conventions defined by the plugin.
Let's start with a new build file and use the Java plugin. We only have to apply the plugin for our build:
apply plugin: 'java'
That's it! Just by adding this simple line, we now have a lot of tasks that we can use to work with in our Java project. To see the tasks that have been added by the plugin, we run the tasks
command on the command line and look at the output:
$ gradle tasks :tasks ------------------------------------------------------------ All tasks runnable from root project ------------------------------------------------------------ Build tasks ----------- assemble - Assembles the outputs of this project. build - Assembles and tests this project. buildDependents - Assembles and tests this project and all projects that depend on it. buildNeeded - Assembles and tests this project and all projects it depends on. classes - Assembles main classes. clean - Deletes the build directory. jar - Assembles a jar archive containing the main classes. testClasses - Assembles test classes. Build Setup tasks ----------------- init - Initializes a new Gradle build. [incubating] wrapper - Generates Gradle wrapper files. [incubating] Documentation tasks ------------------- javadoc - Generates Javadoc API documentation for the main source code. Help tasks ---------- components - Displays the components produced by root project 'getting_started'. [incubating] dependencies - Displays all dependencies declared in root project 'getting_started'. dependencyInsight - Displays the insight into a specific dependency in root project 'getting_started'. help - Displays a help message. model - Displays the configuration model of root project 'getting_started'. [incubating] projects - Displays the sub-projects of root project 'getting_started'. properties - Displays the properties of root project 'getting_started'. tasks - Displays the tasks runnable from root project 'getting_started'. Verification tasks ------------------ check - Runs all checks. test - Runs the unit tests. Rules ----- Pattern: clean<TaskName>: Cleans the output files of a task. Pattern: build<ConfigurationName>: Assembles the artifacts of a configuration. Pattern: upload<ConfigurationName>: Assembles and uploads the artifacts belonging to a configuration. To see all tasks and more detail, run gradle tasks --all To see more detail about a task, run gradle help --task <task> BUILD SUCCESSFUL Total time: 0.849 secs
If we look at the list of tasks, we can see the number of tasks that are now available to us, which we didn't have before; all this is done just by adding a simple line to our build file.
We have several task groups with their own individual tasks, which can be used. We have tasks related to building source code and packaging in the Build tasks
section. The javadoc
task is used to generate Javadoc documentation, and is in the Documentation tasks
section. The tasks for running tests and checking code quality are in the Verification tasks
section. Finally, we have several rule-based tasks to build, upload, and clean artifacts or tasks in our Java project.
The tasks added by the Java plugin are the visible part of the newly added functionality to our project. However, the plugin also adds the so-called convention
object to our project.
A convention
object has several properties and methods, which are used by the tasks of the plugin. These properties and methods are added to our project and can be accessed like normal project properties and methods. So, with the convention object, we can not only look at the properties used by the tasks in the plugin, but we can also change the value of the properties to reconfigure certain tasks.
To work with the Java plugin, we are first going to create a very simple Java source file. We can then use the plugin's tasks to build the source file. You can make this application as complex as you want, but in order to stay on topic, we will make this as simple as possible.
By applying the Java plugin, we must now follow some conventions for our project directory structure. To build the source code, our Java source files must be in the src/main/java
directory, relative to the project directory. If we have non-Java source files that need to be included in the JAR file, we must place them in the src/main/resources
directory. Our test source files need to be in the src/test/java
directory and any non-Java source files required for testing can be placed in src/test/resources
. These conventions can be changed if we want or need it, but it is a good idea to stick with them so that we don't have to write any extra code in our build file, which could lead to errors.
Our sample Java project that we will write is a Java class that uses an external property file to get a welcome message. The source file with the name Sample.java
is located in the src/main/java
directory, as follows:
// File: src/main/java/gradle/sample/Sample.java package gradle.sample; import java.util.ResourceBundle; /** * Read welcome message from external properties file * <code>messages.properties</code>. */ public class Sample { public Sample() { } /** * Get <code>messages.properties</code> file * and read the value for <em>welcome</em> key. * * @return Value for <em>welcome</em> key * from <code>messages.properties</code> */ public String getWelcomeMessage() { final ResourceBundle resourceBundle = ResourceBundle.getBundle("messages"); final String message = resourceBundle.getString("welcome"); return message; } }
In the code, we use ResourceBundle.getBundle()
to read our welcome message. The welcome message itself is defined in a properties
file with the name messages.properties
, which will go in the src/main/resources
directory:
# File: src/main/resources/gradle/sample/messages.properties welcome = Welcome to Gradle!
To compile the Java source file and process the properties file, we run the classes
task. Note that the classes
task has been added by the Java plugin. This is the so-called life cycle task in Gradle. The classes
task is actually dependent on two other tasks—compileJava
and processResources
. We can see this task dependency when we run the tasks
command with the --all
command-line option:
$ gradle tasks --all ... classes - Assembles main classes. compileJava - Compiles main Java source. processResources - Processes main resources. ...
Let's run the classes
task from the command line:
$ gradle classes :compileJava :processResources :classes BUILD SUCCESSFUL Total time: 1.08 secs
Here, we can see that compileJava
and processResources
tasks are executed because the classes
task depends on these tasks. The compiled class file and properties file are now in the build/classes/main
and build/resources/main
directories. The build
directory is the default directory that Gradle uses to build output files.
If we execute the classes
task again, we will notice that the tasks support the incremental build feature of Gradle. As we haven't changed the Java source file or the properties file, and the output is still present, all the tasks can be skipped as they are up-to-date:
$ gradle classes :compileJava UP-TO-DATE :processResources UP-TO-DATE :classes UP-TO-DATE BUILD SUCCESSFUL Total time: 0.595 secs
To package our class file and properties file, we invoke the jar
task. This task is also added by the Java plugin and depends on the classes
task. This means that if we run the jar
task, the classes
task is also executed. Let's try and run the jar
task, as follows:
$ gradle jar :compileJava UP-TO-DATE :processResources UP-TO-DATE :classes UP-TO-DATE :jar BUILD SUCCESSFUL Total time: 0.585 secs
The default name of the resulting JAR file is the name of our project. So if our project is called sample
, then the JAR file is called sample.jar
. We can find the file in the build/libs
directory. If we look at the contents of the JAR file, we see our compiled class file and the messages.properties
file. Also, a manifest file is added automatically by the jar
task:
$ jar tvf build/libs/sample.jar 0 Wed Oct 21 15:29:36 CEST 2015 META-INF/ 25 Wed Oct 21 15:29:36 CEST 2015 META-INF/MANIFEST.MF 0 Wed Oct 21 15:26:58 CEST 2015 gradle/ 0 Wed Oct 21 15:26:58 CEST 2015 gradle/sample/ 685 Wed Oct 21 15:26:58 CEST 2015 gradle/sample/Sample.class 90 Wed Oct 21 15:26:58 CEST 2015 gradle/sample/messages.properties
We can also execute the assemble
task to create the JAR file. The assemble
task, another life cycle task, is dependent on the jar
task and can be extended by other plugins. We could also add dependencies on other tasks that create packages for a project other than the JAR file, such as a WAR file or ZIP archive file:
$ gradle assemble :compileJava UP-TO-DATE :processResources UP-TO-DATE :classes UP-TO-DATE :jar UP-TO-DATE :assemble UP-TO-DATE BUILD SUCCESSFUL Total time: 0.607 secs
To start again and clean all the generated output from the previous tasks, we can use the clean
task. This task deletes the project build
directory and all the generated files in this directory. So, if we execute the clean
task from the command line, Gradle will delete the build
directory:
$ gradle clean :clean BUILD SUCCESSFUL Total time: 0.583 secs
Note that the Java plugin also added some rule-based tasks. One of them was clean<TaskName>
. We can use this task to remove the output files of a specific task. The clean
task deletes the complete build
directory; but with clean<TaskName>
, we only delete the files and directories created by the named task. For example, to clean the generated Java class files of the compileJava
task, we execute the cleanCompileJava
task. As this is a rule-based task, Gradle will determine that everything after clean
must be a valid task in our project. The files and directories created by this task are then determined by Gradle and deleted:
$ gradle cleanCompileJava :cleanCompileJava UP-TO-DATE BUILD SUCCESSFUL Total time: 0.578 secs
3.144.37.38