IntelliJ IDEA Tips & Tricks

History of Gradle Delegation Process in IntelliJ IDEA

Read this post in other languages:

Nowadays, a build tool is an essential part of any project, and IntelliJ IDEA integrates with the majority of them. Among the most popular build tools is Gradle.

We’d like to give a brief historical overview of its integration with IntelliJ IDEA and the delegation process implemented inside the IDE.

Starting point

IntelliJ IDEA has been on the market for a longer period than any other build tool and has been offering its native build system with great success for many years. The IntelliJ IDEA build system has always stood out as the best option for tasks such as compiling, running tests, and packaging into JARs.

Considering that a developer’s primary focus is often on compiling and running tests, the fast feedback cycle of the building process is crucial, and we excelled in executing JUnit and TestNG tests, as well as performing incremental compilation.

Before Gradle

When Maven came on the scene with its great ability to manage project dependencies, we embraced it, utilized its project structure, and delegated downloading and resolving dependencies to Maven (but left the building process to IntelliJ IDEA).

We were able to replicate Maven’s build process in the IntelliJ IDEA build system. Based on the Maven project model, IntelliJ IDEA could build projects with minimal additional steps. At the same time, we further enhanced the building process by developing a mechanism that efficiently retrieved information about resource processing, including the generation of the MANIFEST.mf file from the pom.xml.

We then took the results of that building process and applied them to our native processes of executing tests.

Through this improvement, we were able to cover all of the necessary scenarios for successfully building Maven projects with IntelliJ IDEA.

We continue using this setup for Maven projects – retrieving the necessary information from Maven and using the native IntelliJ IDEA mechanism for building and launching projects, even for such popular tools as Spring Boot and Micronaut.

Integrating Gradle

When Gradle appeared on the market, it gave users the ability to perform better customization of their build processes and add more functionality to them.

At that time, we decided to start with an approach similar to the one we used with Maven. This means we would let Gradle take care of the dependencies and retrieve the necessary information, but IntelliJ IDEA would compile the code, run tests, and build projects.

However, a Gradle project model turned out to be a bit too flexible. You could have different source sets or use various languages such as Groovy, Scala, or Kotlin in the build script. Moreover, you could write imperative code right in the build script giving direct instructions on the desired behavior and settings for your build system.

For instance, it is possible to start a database before the run or before the test run. Another example is that, compared to Maven with its static configuration, Gradle build scripts allow for the execution of arbitrary code during resource processing. Such configurations are quite hard to reproduce using IntelliJ IDEA capabilities.

It became evident that we were good when it came to standard operations, but custom ones, such as processing resources along with other custom tasks, became quite difficult for us to control, maintain, and, most importantly, replicate in the IntelliJ IDEA build system.

So, we made the decision to delegate test running to Gradle:

When you run your test, the Gradle test task is executed along with other tasks that are part of the Gradle build cycle as shown below:

Besides that, IntelliJ IDEA offers additional functionality. For example, the tests you need to run might be distributed across various source sets. You may have integration tests in one source set and functional tests in another.

IntelliJ IDEA is able to correctly determine the test task for a specific test file and its location, ensuring efficient execution of the relevant tests.

Additionally, IntelliJ IDEA provides information on what level the test was performed – method, class, or package. For example, by default, Gradle executes all the tests in the source set.

However, IntelliJ IDEA applies the filtering pattern and, in the Run tool window, displays a message letting you know exactly where the test was executed:

Overall, the test delegation to Gradle was quite the success.

The next logical step was to delegate Build and Run actions to Gradle as well. Ultimately, this delegation became the default one.

So, now when you use the Run action in your application, it’s used in the Gradle context and done on the fly.

We are doing something similar to the existing Gradle application plugin, creating a task with the JavaExec type that runs the main class. This ensures the maximum correctness of the application run configuration.

When you trigger Build in delegation mode, IntelliJ IDEA generates a list of commands in Gradle that need to be executed based on the modified modules in a project.You can view this information in BuildOutput:

IntelliJ IDEA can also detect files that were modified in different modules and build only the modified part.

Currently, you can choose from two delegation mode options: Gradle and IntelliJ IDEA.

  • Gradle: When the process is delegated to Gradle, it’s a bit slower than our native build system and a small overhead is present. Sometimes, in delegated mode, the Gradle daemon needs to be rerun.
    Additionally, Gradle keeps its lifecycle process, rerunning the Gradle model and checking the build scripts and its file system, even if there is compiled code done by IntelliJ IDEA.
  • IntelliJ IDEA: If there is no complex setup in your Gradle project, you can use IntelliJ IDEA for a fast building process.

Also note that annotation processing is supported during the compilation process. However, there are some edge cases that are quite difficult to handle when the code is compiled by IntelliJ IDEA, for example, when the annotation processor is defined in one of the Gradle subprojects.

So, this is the point we are at right now. We’re still experimenting with Spring and Micronaut run configurations in delegated mode and are working constantly on improving the Gradle delegation process in the IDE.

We hope that we gave you a glimpse at the hows and whys, as well as an overview of the delegation process in IntelliJ IDEA.

As always, we’d love to hear your feedback. You can leave a comment below or use our issue tracker for feature requests.

Happy developing!

image description