Maven Extension to forcibly resolve a dependency, how dangerous is it?

Viewed 23

I've got a multi-module Maven project, consisting in the following - simplified - structure

parent
|__ aggregator
   |__ project1
|__ aggregator
   |__ project2
|__ aggregator
   |__ project3

where project3 depends on project2, and project2 depends on project1.

I'd like to be able to invoke lifecycle phases such as initialize, generate-sources, process-resources, without having to compile, or install locally beforehand. To be practical, this is what a new developer should do to be able to start coding:

git clone my-project
cd my-project
mvn initialize

After reading half a hundred answers about multi-module Maven builds on StackOverflow and a dozen blog posts, and after debugging the dependencies resolution process myself in search for the miracle, I came to the realization this is not possible by default.

I could, however, use the pluggable Extensions mechanism to inject my own Plexus Component to change a default behavior.

Maven uses a WorkspaceReader to try and resolve dependencies in the local workspace, when they cannot be found in remote or local repositories. Specifically the default reader is ReactorReader.

If we take a look a the ReactorReader#findArtifact method, and at the private ReactorReader#find method, we can clearly see that what Maven evaluates is the lifecycle phase, which must be at least compile, and the presence of the packaging type in the COMPILE_PHASE_TYPES list.

Since I want to invoke, e.g. initialize, and since my packaging type is not on that list, ReactorReader#findArtifact returns null, telling Maven "hey I can't find this dependency, abort".
But damn, I'm not trying to compile! I'm just trying to invoke some goals on initialize, which do not require dependencies.

And here comes the idea: contributing my own WorkspaceReader, which for phases before compile and for workspace project only returns a dummy File instance. A simplified snippet is:

@Override
public File findArtifact(final Artifact artifact) {
  // defaultReader is ReactorReader, and is injected through @Requirement or @Named
  final var file = defaultReader.findArtifact(artifact);
  
  // If the dependency has not been found by the default ReactorReader,
  // and if it meets certain conditions, let's return a dummy file
  if (file == null && isForcible(artifact)) {
    final var localProject = getProject(artifact);
    return new File(localProject.getBuild().getOutputDirectory());
  }
  
  return file;
}

And that's it. What's cool is that it works, I'm able to execute whatever phase prior to compile without errors.

The real question is, how dangerous is this? What could I break? What could go wrong?
Funny journey tho, spent an entire week on this.

0 Answers
Related