0

I have a multi-module maven project, and I'd like to collect some information about all modules using a custom plugin.

I managed to get what I want for each module. Due to the nature of the information I collect, it would be much more effective to collect it in memory and dump the consolidated results at the very end.

Custom Mojo that illustrates the idea (and I know that does not work, see below):

@Mojo(name = "dummy")
public class DummyMojo extends AbstractMojo {

    private static Set<String> data = Collections.synchronizedSet(new HashSet<String>());

    @Parameter(defaultValue = "${project}", readonly = true)
    private MavenProject mavenProject;

    @Override
    public void execute() throws MojoExecutionException, MojoFailureException {
        data.add(mavenProject.getArtifactId());
        getLog().info("Execution #" + data.size());
    }

}

This collects artifact IDs of all my modules (this is just an example to simplify, in reality I collect some other irrelevant stuff).

I'd like to dump the result at the very end of the build.

If I run this, I observe that 2 instances are created (I have >100 modules):

% mvn com.company:foo:1.0-SNAPSHOT:dummy | grep 'Execution #'
[INFO] Execution #1
...
[INFO] Execution #6
[INFO] Execution #13
[INFO] Execution #14
[INFO] Execution #15
[INFO] Execution #7
[INFO] Execution #8
[INFO] Execution #9
....
[INFO] Execution #90
[INFO] Execution #91
[INFO] Execution #13
[INFO] Execution #92
[INFO] Execution #14
[INFO] Execution #15
[INFO] Execution #39
[INFO] Execution #40
[INFO] Execution #41

So I observe that I cannot collect data for each module and share it across each Mojo execution using a static variable.

If I also print PID and ClassLoader, I observe that it all happens in the same JVM process, but a second classloader is used for some modules. I vaguely know why: the affected modules (legacy stuff) use an exotic plugin (NetBeans Maven plugin), and today I'm discovering that I have to add that disappointment to the heap of issues it caused us.

Anway, questions:

1) Is there a correct way to collect data in memory across all executions of a given Mojo during a single multimodule build? (Or is there a way to ensure all executions happen in same JVM & same class loader?)

2) How can I detect end of build, once all modules have been visited? I suppose there is something on the build I can observe... Sorry my understanding is incomplete there... Lifecycle, reactor... What concept am I missing to implement this?

I'm ready to read about how that is a Bad Idea! I'm just experimenting at this point: if I'm misguided I do need "reguidance".

I checked that Q/A but it was about sharing across 3 different Mojos for a single module.

(For now I can dump the results every time, the last one overwrites the previous result, it's OK for my use case, but if I can improve that, it would be great)

Hugues M.
  • 19,846
  • 6
  • 37
  • 65
  • What kind of data would you like to collect? You example shows your are using `mavenProject.getArtifactId()` ? Do you have the code for example on Github or simething alike? – khmarbaise May 23 '17 at 17:47
  • I collect the transitive list of dependencies, and put that list of GAVs in a text file. For a time I was using the standard maven dependency plugin, but 1) the existing options for output are very limited, and 2) it is implemented using old complicated APIs, I am not able to understand the code so I cannot develop anything based on that. Nowadays (Maven 3) collecting dependencies is [very easy](https://stackoverflow.com/a/42559904/6730571) (see my comment to that answer ^^), and a custom plugin seemed easy to do... until I found this issue on multimodule builds. – Hugues M. May 23 '17 at 18:00
  • I think I can put up a small runnable example on GitHub, that will be more representative of the actual problem I'm trying to solve. Not sure I can easily reproduce the ClassLoader issue, though... – Hugues M. May 23 '17 at 18:11
  • Today again I needed to detect end of build (Q#2), and I realized sonar-scanner-maven must do this because it only does its magic at the very end of the multimodule build. Bingo... but it uses an [ugly trick](https://github.com/SonarSource/sonar-scanner-maven/blob/3.4.0.905/src/main/java/org/sonarsource/scanner/maven/SonarQubeMojo.java), incrementing a counter for each visited "project" and doing the work when total is reached :-/ Dear Maven, can you not offer something simpler? – Hugues M. Apr 12 '18 at 17:04

1 Answers1

0

SonarQube does this in sonar-scanner-maven, see SonarQubeMojo.

0) Mojo has annotation aggregator = true

1) Data is collected in a static variable in the mojo

2) They determine "end of build" by counting visited modules and comparing that to expected total. If this is not last module then do nothing (or collect what needs collecting...), if it is then run the thing (consolidate results).

Hugues M.
  • 19,846
  • 6
  • 37
  • 65