Gradle

Gradle Goodness: Grouping Version Catalog Dependencies Into Bundles

Posted on by  
Hubert Klein Ikkink

The version catalog in Gradle is very useful to define a list of dependencies in one single place. In our build script we references dependencies from the version catalog using type safe accessors when we define a dependency for a configuration. Sometimes multiple dependencies belong to each other and are used in combination with each other. In the version catalog we can define bundles of such dependency groups. Instead of referencing each dependency individually we can reference a bundle from the version catalog in our build script. This keeps our build script cleaner and updating a bundle only needs a change in the version catalog.

Continue reading →

Gradle Goodness: Defining Plugin Versions Using Version Catalog

Posted on by  
Hubert Klein Ikkink

A version catalog in Gradle is a central place in our project where we can define dependency references with their version or version rules. A dependency reference is defined using an identifier with a corresponding dependency definition containing the coordinates of the dependency. Now we can reference the dependency using the identifier in for example a dependency configuration, e.g. implementation(libs.spring.core). If there is a version change we want to apply we only have to make the change in our version catalog. An added bonus is that Gradle generates type safe accessors for the identifier we use in our version catalog, so we can get code completion in our IntelliJ IDEA when we want to reference a dependency from the version catalog.

Besides dependencies we need to build and test our software we can also include definitions for Gradle plugins including their version.

Continue reading →

Gradle Goodness: Create Properties File With WriteProperties Task

Posted on by  
Hubert Klein Ikkink

If we need to create a Java properties file in our build we could create a custom task and use the Properties class to store a file with properties. Instead of writing our custom task we can use the task WriteProperties that is already part of Gradle. Using this task Gradle will not add a timestamp in the comment to the properties file. Also the properties are sorted by name, so we know the properties are always in the same order in the output file. Finally, a fixed line separator is used, which is \n by default, but can be set via the task property lineSeparator.

To define the properties that need to be in the output file we can use the property method for a single property, or we can use properties method with a Map argument to set multiple properties.

Continue reading →

Gradle Goodness: Add Support For "Scratch" Files To Java Project

Posted on by  
Hubert Klein Ikkink

When working on a Java project, we might want to have a place where we can just play around with the code we write. We need a "scratch" file where we can access the Java classes we write in our main sourceset. The scratch file is actually a Java source file with a main method where we can create instances of the Java code we write and invoke methods on them. This gives back a fast feedback loop, and we can use it to play around with our Java classes without the need to write a test for it. It gives great flexiblity during development. We must make sure the scratch file will not be packed in the JAR file with our production code.

To support this in our Gradle build file we can add a new sourceset that can access all classes we write in the main sourceset. Also we want to have new configurations for this sourceset so we can add dependencies that are only used by our scratch file. And finally we want a new task to run our scratch file. By default our scratch file will not be part of the JAR file with the classes from the main sourceset.

Continue reading →

Gradle Goodness: Enabling Preview Features For Java

Posted on by  
Hubert Klein Ikkink

Java introduced preview features in the language since Java 12. This features can be tried out by developers, but are still subject to change and can even be removed in a next release. By default the preview features are not enabled when we want to compile and run our Java code. We must explicitly specify that we want to use the preview feature to the Java compiler and Java runtime using the command-line argument --enable-preview. In Gradle we can customize our build file to enable preview features. We must customize tasks of type JavaCompile and pass --enable-preview to the compiler arguments. Also tasks of type Test and JavaExec must be customized where we need to add the JVM argument --enable-preview.

In the following Gradle build script written in Kotlin we have a Java project written with Java 15 where we reconfigure the tasks to enable preview features:

Continue reading →

Gradle Goodness: Setting Plugin Version From Property In Plugins Section

Posted on by  
Hubert Klein Ikkink

The plugins section in our Gradle build files can be used to define Gradle plugins we want to use. Gradle can optimize the build process if we use plugins {…​} in our build scripts, so it is a good idea to use it. But there is a restriction if we want to define a version for a plugin inside the plugins section: the version is a fixed string value. We cannot use a property to set the version inside the plugins section. We can overcome this by using a pluginsManagement section in a settings file in the root of our project. Inside the pluginsManagement section we can use properties to set the version of a plugin we want to use. Once it is defined inside pluginsManagement we can use it in our project build script without having the specify the version. This allows us to have one place where all plugin versions are defined. We can even use a gradle.properties file in our project with all plugin versions and use that in pluginsManagement.

In the following settings file we use pluginsManagement to use a project property springBootPluginVersion to set the version to use for the Spring Boot Gradle plugin.

Continue reading →

Gradle Goodness: Shared Configuration With Conventions Plugin

Posted on by  
Hubert Klein Ikkink

When we have a multi-module project in Gradle we sometimes want to have dependencies, task configuration and other settings shared between the multiple modules. We can use the subprojects or allprojects blocks, but the downside is that it is not clear from the build script of the subproject where the configuration comes from. We must remember it is set from another build script, but there is no reference in the subproject to that connection. It is better to use a plugin with shared configuration and use that plugin in the subprojects. We call this a conventions plugin. This way it is explicitly visible in a subproject that the shared settings come from a plugin. Also it allows Gradle to optimize the build configuration.

Continue reading →

Gradle Goodness: Replace Files In Archives

Posted on by  
Hubert Klein Ikkink

Sometimes we might need to replace one or more files in an existing archive file. The archive file could be a zip, jar, war or other archive. Without Gradle we would unpack the archive file, copy our new file into the destination directory of the unpacked archive and archive the directory again. To achieve this with Gradle we can simply create a single task of type Zip. To get the content of the original archive we can use the project.zipTree method. We leave out the file we want to replace and define the new file as replacement. As extra safeguard we can let the tsak fail if duplicate files are in the archive, because of our replacement.

The following code shows an example of a task to replace a README file in an archive sample.zip using Groovy and Kotlin DSL. First the Groovy DSL:

Continue reading →

Gradle Goodness: Stop Build After One Failing Test

Posted on by  
Hubert Klein Ikkink

Normally when we run tests in our Gradle build, all our tests are executed and at the end we can see which tests are failing. But what if we want to let the build fail at the first failing test? Especially for a large test suite this can save a lot of time, because we don’t have to run all (failing) tests, we immediately get informed that at least one test is failing.

We can do this by passing the command-line option --fail-fast when we run the test task in Gradle. With this option Gradle will stop the build and report a failure at the first failing test. Instead of passing the command-line option --fail-fast we can set the property failFast of the test task to true. Using the property failFast allows to still fail the build on the first failing test even if we for example run a build task that depends on the test task. The command-line option --fail-fast only works if we run the test task directly, not if it is part of the task graph for our build when we run another task.

Continue reading →

Gradle Goodness: Use bill of materials (BOM) As Dependency Constraints

Posted on by  
Hubert Klein Ikkink

Since Gradle 5 we can easily use a bill of materials (BOM) in our build file to get recommended dependency versions. The dependency versions defined in the BOM are dependency constraints in Gradle. This means the dependencies we define in our build that are part of the BOM don’t need a version, because the version is resolved via the dependency constraint that is defined in the BOM. Also transitive dependency versions are resolved using the BOM if applicable. We use the dependency handler method platform to define the BOM we want to import. The versions in the BOM are recommendations. We can override the recommendation by specifying the version for a dependency found in the BOM with an explicit version.

Continue reading →

Gradle Goodness: Manage Dependency Versions With Dependency Constraints

Posted on by  
Hubert Klein Ikkink

From Maven builds we know the dependencyManagement section in our POM file. In the section we can describe dependencies with their version and later in the dependencies section we can refer to the dependency without the version. We can use dependency constraints in Gradle to do the same thing. A dependency constraint can be used to define the version or version range for a dependency defined in our scripts or a transitive dependency. Just like a dependency the dependency constraint is defined for a configuration, so we can fine tune the constraints to the correct configuration.

Using dependency constraints in a multi-project build allows us to define the dependency versions in the root build file and define project dependencies per project without a version. The version will then be used from the dependency constraint we defined in the root build file.

Continue reading →

shadow-left