Skip to content

Commit

Permalink
DevMojo: support managed dependencies for APT plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
FroMage committed Jan 12, 2024
1 parent e7c12ca commit adad6d0
Showing 1 changed file with 54 additions and 2 deletions.
56 changes: 54 additions & 2 deletions devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Properties;
import java.util.Scanner;
Expand All @@ -49,6 +50,7 @@
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.BuildBase;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.DependencyManagement;
import org.apache.maven.model.Plugin;
import org.apache.maven.model.PluginExecution;
import org.apache.maven.model.Profile;
Expand Down Expand Up @@ -715,6 +717,9 @@ private void executeGoal(PluginExec pluginExec, String goal, Map<String, String>
}

private List<String> readAnnotationProcessors(Xpp3Dom pluginConfig) {
if (pluginConfig == null) {
return Collections.emptyList();
}
Xpp3Dom annotationProcessors = pluginConfig.getChild("annotationProcessors");
if (annotationProcessors == null) {
return Collections.emptyList();
Expand All @@ -731,6 +736,9 @@ private List<String> readAnnotationProcessors(Xpp3Dom pluginConfig) {
}

private Set<File> readAnnotationProcessorPaths(Xpp3Dom pluginConfig) throws MojoExecutionException {
if (pluginConfig == null) {
return Collections.emptySet();
}
Xpp3Dom annotationProcessorPaths = pluginConfig.getChild("annotationProcessorPaths");
if (annotationProcessorPaths == null) {
return Collections.emptySet();
Expand All @@ -739,6 +747,10 @@ private Set<File> readAnnotationProcessorPaths(Xpp3Dom pluginConfig) throws Mojo
Set<File> elements = new LinkedHashSet<>();
try {
List<org.eclipse.aether.graph.Dependency> dependencies = convertToDependencies(paths);
// NOTE: The Maven Compiler Plugin also supports a flag (disabled by default) for applying managed dependencies to
// the dependencies of the APT plugins (not them directly), which we don't support yet here
// you can find the implementation at https://github.com/apache/maven-compiler-plugin/pull/180/files#diff-d4bac42d8f4c68d397ddbaa05c1cbbed7984ef6dc0bb9ea60739df78997e99eeR1610
// when/if we need it
CollectRequest collectRequest = new CollectRequest(dependencies, Collections.emptyList(),
project.getRemoteProjectRepositories());
DependencyRequest dependencyRequest = new DependencyRequest();
Expand All @@ -756,25 +768,66 @@ private Set<File> readAnnotationProcessorPaths(Xpp3Dom pluginConfig) throws Mojo
}
}

private List<org.eclipse.aether.graph.Dependency> convertToDependencies(Xpp3Dom[] paths) {
private List<org.eclipse.aether.graph.Dependency> convertToDependencies(Xpp3Dom[] paths) throws MojoExecutionException {
List<org.eclipse.aether.graph.Dependency> dependencies = new ArrayList<>();
for (Xpp3Dom path : paths) {
String type = getValue(path, "type", "jar");
ArtifactHandler handler = artifactHandlerManager.getArtifactHandler(type);
// WATCH OUT: this constructor turns any null values into empty strings
org.eclipse.aether.artifact.Artifact artifact = new DefaultArtifact(
getValue(path, "groupId", null),
getValue(path, "artifactId", null),
getValue(path, "classifier", null),
handler.getExtension(),
getValue(path, "version", null));
if (toNullIfEmpty(artifact.getVersion()) == null) {
artifact = artifact.setVersion(getAnnotationProcessorPathVersion(artifact));
}
Set<org.eclipse.aether.graph.Exclusion> exclusions = convertToAetherExclusions(path.getChild("exclusions"));
dependencies.add(new org.eclipse.aether.graph.Dependency(artifact, JavaScopes.RUNTIME, false, exclusions));
}
return dependencies;
}

private String getAnnotationProcessorPathVersion(org.eclipse.aether.artifact.Artifact annotationProcessorPath)
throws MojoExecutionException {
List<Dependency> managedDependencies = getProjectManagedDependencies();
return findManagedVersion(annotationProcessorPath, managedDependencies)
.orElseThrow(() -> new MojoExecutionException(String.format(
"Cannot find version for annotation processor path '%s'. The version needs to be either"
+ " provided directly in the plugin configuration or via dependency management.",
annotationProcessorPath)));
}

private Optional<String> findManagedVersion(
org.eclipse.aether.artifact.Artifact artifact, List<Dependency> managedDependencies) {
// here, Dependency uses null, while artifact uses empty strings
return managedDependencies.stream()
.filter(dep -> Objects.equals(dep.getGroupId(), artifact.getGroupId())
&& Objects.equals(dep.getArtifactId(), artifact.getArtifactId())
&& Objects.equals(dep.getClassifier(), toNullIfEmpty(artifact.getClassifier()))
&& Objects.equals(dep.getType(), toNullIfEmpty(artifact.getExtension())))
.findAny()
.map(org.apache.maven.model.Dependency::getVersion);
}

private String toNullIfEmpty(String value) {
if (value != null && value.isBlank())
return null;
return value;
}

private List<Dependency> getProjectManagedDependencies() {
DependencyManagement dependencyManagement = project.getDependencyManagement();
if (dependencyManagement == null || dependencyManagement.getDependencies() == null) {
return Collections.emptyList();
}
return dependencyManagement.getDependencies();
}

private String getValue(Xpp3Dom path, String element, String defaultValue) {
Xpp3Dom child = path.getChild(element);
// don't bother filtering empty strings or null values, DefaultArtifact will turn nulls into empty strings
if (child == null) {
return defaultValue;
}
Expand Down Expand Up @@ -1505,7 +1558,6 @@ private void setAnnotationProcessorFlags(MavenDevModeLauncher.Builder builder) {
break;
}
}

if (compilerMavenPlugin == null) {
return;
}
Expand Down

0 comments on commit adad6d0

Please sign in to comment.