Gradle - notes
Notes about Gradle
What should I know about Gradle? How to create a project with submodules? Or maybe: how to create simple project? Or how to use Gradle with Kotlin?
This post is a set of very random notes, too chaotic to treat them as any valuable source of information. I write as I go through the Gradle documentation.
Information you can find here may be not only random, but also factually incorrect. I’m still building my mental model of how Gradle works.
So please don’t quote me on anything you read here 😄
Kinds of scripts
There are three kinds:
- main build script which is represented by a class Project
- there are initializing scripts which are used to prepare the environment before proper main script is executed; don’t have access to buildSrc
- scripts with settings which are used to create and configure the hierarchy of projects which are parts of the build; they are represented by a class Settings
Gradle DSL is described in Gradle Build Language Reference
Lifecycle
A commandline call gradle ...
starts a lifecycle of three phases, which are, in order:
- initialization - Gradle finds out what projects need to be build and create an instance of a
Project
for each of them - configuration - when objects are configured in a project (or projects): in this phase build scripts for each of the project are executed (note: the code in task definitions is executed unless it is closed in
doLast
ordoFirst
closure) - exeuction - Gradle finds out what tasks (created and configured in configuration phase) needs to be executed and executes them
Notes about how to read Groovy code
How to write groovy build scripts: primer
Proerties, methods, blocks
Unqualified properties map to methods in Project
class, and inside a block they may map to methods of delegated object)
The signature of such methods denotes the parameters, and if the last one is of type closure or Action then this is usually visible in the syntax as a code block.
In general, properties may come from different sources:
- Project object
- extra properties: arbitrary key-value map
- extentions properties which are usually added to the project by plugins and are avaibale as read only, named after the extension
- convention propertyes also added by plugins; can be modifiable; represented by Convention
- tasks declared in the scripts; are available through their name: for each task a property with the same name as a task is created; such properties are read-only
Dependencies used/required by the build script itself
Can be declaed inside buildscript
block (where an instance of ScriptHandler is configured) - they will be added to the classpath of the script when it is executed, for example:
|
|
In the above example dependencies {...}
is a call to the method getDependencies()
on an instance of Scripthandler
(which returns DependencyHandler). Dependencies are grouped in configurations - in the example there is a configuration named “classpath” .
Configuration is a named set of dependencies.
In general, dependencies section looks like this:
|
|
Java - plugins
Two basic types of projects created in Java are library or application. Each one has a separate plugin: java-library and application, respectively. Both are based in java
plugin. The separation allows for interesting optimizations regarding the configirations (api
and implementation
in a definition of a dependency for a library) that influence the classpath.
application
In earlier versions of Gradle plugins were applied to a project by a call to apply
, but now the recommended way is to use plugins block, for example:
|
|
Running application with commandline arguments:
|
|
java library
Java Library Plugin configures a project as a Java library. It has three standard configurations which can be used in build script:
- implementation - here one can place dependencies needed to compile the production code of the library, but which are not part of an API exposed by the library
- API - dependencies needed to compile the production code of the library which should also be visible from the outside of the library (e.g. by an application that is using the library)
- testImplementation - dependencies needed to compile and run test sources
What I’ve understood is that introduction of the split od dependencies (between api and implementation) allows to achieve smaller classpath for a library or application that is using this library; it does not have to use all transitive dependencies of the library, only those defined as api.
Wait a sec. This reminds me of Java modules and inter-module requirements (requires oraz requires transitive). How are Java modules and Gradle configurations connected? Let’s check.
Modules usage
Here is the documentation about how to use modular java library.
That’s interesing - right now (October 2021) Java modules and Gradle configurations are mapped one-to-one but Gradle does not check the consistency bewteen requirements of Java modules and library configuration types.
Declaring main class’ module
Running a class in multimodule application (Java 9 or later) you need to also provide the name of the main module where your main class resides:
|
|
Excercises
Here are some exercises which I’ve prepared for myself to better know Gradle. They are, more or less, of increasing difficulty and follow normal requirements expansion process - or rather normal development process.
Initial build scripts should be modified in order to cover all of the following aspects as you go:
- create a script for a simple java app with unit tests
- run the application (using Gradle)
- run the tests (…)
- extract part of the code to external library - define it as main build’s subproject
- use the library in the application - how to check if the dependencies from library’s
implementation
configuration are in fact not present on the classpath of the app? - change the app and library to be modular (as of Java 9 or later)
- run modular application (…)
- run tests
- create a distribution (jlink? or default solution with zip/tar and running scripts?)
- create GUI app which has its splashscreen with a date and SHA of the commit from which the build comes from
- use a database - different for tests and different for application (don’t use Spring Boot)
Good luck!