Grigoriy Myasoedov
Posted on November 5, 2023
Hello, my name is Grigory. I am a Java developer with 15+ experience.
In my work I use Intellij IDEA as IDE and Maven as build tool for most projects. During my work, I had to deal with problems when a Maven project was successfully assembled via the command line, but was not imported into IDEA. Typically, such problems occur when additional plugins are used to resolve dependencies. For example: eclipse OSGI project (but not only). Therefore, let me introduce you to my plugin for working with Maven for IDEA - GMaven, which is designed to solve this problem.
IDEA Bundled Maven-plugin problems
I am familiar with the source codes of the IDEA bundled Maven-plugin (IBMP). IBMP for resolving dependencies and obtaining project models uses its own custom process, which is somewhat reminiscent of a maven daemon. It is built from low-level Maven service components: ProjectBuilder, ModelInterpolator, ProjectDependenciesResolver and etc.
Due to complete customization and reuse of the their Maven process, they received the following advantages:
- the process is more lightweight than the original maven;
- due to this, the speed of resolving dependencies and obtaining a projects model is higher;
- it's easier to add features for the IDE.
But there are also problems:
- If a new features appears in Maven, then as a rule you have to manually add it to IBMP process;
- Maven changes frequently inside - method signatures changes, new classes appear. This causes backward compatibility problems (recent problems: maven3.8.5, maven4.0-aplha5, maven4.0-aplha7, Maven 4: Cannot sync a project using model version 4.1.0).
- hard to maintain;
To summarize, we can say that the main problem is IBMP that its process for resolving dependencies differs from the original Maven process when launched via the command line.
My idea
So I had an idea - why not resolve the project's dependencies using a native Maven plugin and thereby use the full original Maven lifecycle.
Let's look at an example of the simplest Maven plugin:
@Mojo(
name = "my_task_name", defaultPhase = NONE,
aggregator = true, requiresDependencyResolution = TEST
)
public class ResolveProjectMojo extends AbstractMojo {}
Even such a simple plugin, thanks to the parameter requiresDependencyResolution = TEST (TEST is the top-level scope), will download all dependencies if necessary and resolve them, adding resolved artifacts to the Maven project model. My Maven-plugin code is not much more complicated than this example. Its main idea is to resolve dependencies and extracting the configuration of a number of plugins necessary for the correct import of the project model into IDEA.(maven-compiler-plugin, build-helper-maven-plugin and etc). As a result, I wrote my own plugin for Intellij IDEA to support Maven - GMaven (because my name is Grigoriy 🙂), which uses the native Maven plugin to resolve dependencies.
Also, I moved the maven-plugin to a separate repository on GitHub and published the artifact in Maven Central.
The project import process consists of the following steps:
- From the IDEA plugin I start the simple maven process;
- The result project model, with all resolved dependencies, is returned via file in JSON format;
- Data from the file is loaded into the IDEA project structure.
This is what the import process looks like in the build window. We see the full Maven log: how the process was launched and what is happening in it.
As a result we get:
- a very simple process of interacting with Maven, which consists of running the maven goal;
- a full Maven life cycle with all current features, which excludes bugs from the category of something we didn’t take into account when obtaining the project model;
- a full-fledged Maven log, which makes it easier to maintain the plugin and solve problems.
Additional features
- Using the whole project context for task execution wiki.
- Delegating tasks execution to Maven Daemon wiki.
- Refused to render the full dependency tree in the build tool window. As a result, it renders much faster, especially noticeable on large projects, where there are thousands of dependencies and it is not convenient to search in it. Instead there is one node - “dependencies”. Click to open the Dependency Analyzer window with a convenient mechanism for searching and analyzing dependencies, which lazily loads the dependency tree. As a result, GMaven-plugin stores less state.
Results of projects import time measurements
IDEA 2023.2, -Xmx4g, i7-10875H, 32gb.
GMaven (seconds) | IDEA Maven (seconds) | |
---|---|---|
Quarkus (~1100 modules) | 110 | 60 |
Dbeaver (~150 modules) | 60 | - (Error) |
Spring-Boot-2.1.x (~100 modules) | 20 | 12 |
Maven 3.8.x (15 modules) | 2 | 2 |
- all dependencies at the time of measurements were already in the local repository;
In general, the IBMP, due to its customization and incremental update functionality, works faster, but this is noticeable on large projects. On small projects with up to 50 modules, import times are comparable.
Result
GMaven-plugin has fewer features, no Maven indexes, no incremental import, fewer quick fixes, but it is much simpler and, in theory, more stable, stores less state and consumes less memory.
For example, maven indexes have a number of problems in the IBMP and affect performance. Instead of calculating and storing maven-indexes myself, I use HTTP requests to the server https://search.maven.org. Also, my plugin has fewer problems with backward compatibility, the Maven-plugin API is much more stable and changes less often. And uses a full-fledged Maven lifecycle to resolve dependencies.
If you have problems with importing a Maven project into IDEA with a bundled maven-plugin or you are just interested in trying my plugin, then I would be glad to receive any feedback. If we find any problems, feel free to create an issue.
Required version of IntelliJ IDEA 2022.2+ (but there is also a cut-down port for 2021.3)
Posted on November 5, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.