diff --git a/rewrite-maven/src/main/java/org/openrewrite/maven/tree/ResolvedPom.java b/rewrite-maven/src/main/java/org/openrewrite/maven/tree/ResolvedPom.java index dcebe01b02c..2969265eed7 100644 --- a/rewrite-maven/src/main/java/org/openrewrite/maven/tree/ResolvedPom.java +++ b/rewrite-maven/src/main/java/org/openrewrite/maven/tree/ResolvedPom.java @@ -508,7 +508,21 @@ private void mergeRequestedDependencies(List incomingRequestedDepend //If it's empty, we ensure to create a mutable list. requestedDependencies = new ArrayList<>(incomingRequestedDependencies); } else { - requestedDependencies.addAll(incomingRequestedDependencies); + // When a child dependency has overriden a parent dependency (either version or scope) + // We shouldn't add the parent definition when requested; the child takes precedence + for (Dependency incReqDep : incomingRequestedDependencies) { + boolean found = false; + for (Dependency reqDep : requestedDependencies) { + if (reqDep.getGav().getGroupId().equals(incReqDep.getGav().getGroupId()) + && reqDep.getArtifactId().equals(incReqDep.getArtifactId())) { + found = true; + break; + } + } + if (!found) { + requestedDependencies.add(incReqDep); + } + } } } } diff --git a/rewrite-maven/src/test/java/org/openrewrite/maven/AddDependencyTest.java b/rewrite-maven/src/test/java/org/openrewrite/maven/AddDependencyTest.java index 9a5249a41d9..91248547837 100644 --- a/rewrite-maven/src/test/java/org/openrewrite/maven/AddDependencyTest.java +++ b/rewrite-maven/src/test/java/org/openrewrite/maven/AddDependencyTest.java @@ -22,6 +22,7 @@ import org.junit.jupiter.params.provider.ValueSource; import org.openrewrite.DocumentExample; import org.openrewrite.Issue; +import org.openrewrite.java.ChangePackage; import org.openrewrite.java.JavaParser; import org.openrewrite.test.RecipeSpec; import org.openrewrite.test.RewriteTest; @@ -1283,6 +1284,186 @@ void addDependenciesOnEmptyProject() { ); } + @Test + void dependencyThatIsTransitivelyProvidedWithWrongScopeShouldBeAdded() { + rewriteRun( + spec -> spec + .parser(JavaParser.fromJavaVersion() + .dependsOn( + """ + package main.java.checkerframework.checker.nullness.qual; + public @interface NonNull {} + """ + ) + ) + .recipes( + new AddDependency("org.checkerframework", "checker-qual", "3.44.0", + null, null, null, "main.java.checkerframework..*", null, null, null, null, + true), + new ChangePackage("main.java.checkerframework", "org.checkerframework", true) + ), + mavenProject("parent", + pomXml( + """ + + com.mycompany.app + parent + 1 + + child + + + + + com.google.guava + guava + 31.1-jre + + + + """ + ), + mavenProject("child", + srcMainJava( + java( + """ + import main.java.checkerframework.checker.nullness.qual.NonNull; + class Foo {} + """, + """ + import org.checkerframework.checker.nullness.qual.NonNull; + class Foo {} + """ + ) + ), + pomXml( + """ + + + com.mycompany.app + parent + 1 + ../pom.xml + + child + + + com.google.guava + guava + 31.1-jre + test + + + + """, + """ + + + com.mycompany.app + parent + 1 + ../pom.xml + + child + + + org.checkerframework + checker-qual + 3.44.0 + + + com.google.guava + guava + 31.1-jre + test + + + + """ + ) + ) + ) + ); + } + + @Test + void dependencyThatIsTransitivelyProvidedWithCorrectScopeShouldNotBeAdded() { + rewriteRun( + spec -> spec + .parser(JavaParser.fromJavaVersion() + .dependsOn( + """ + package main.java.checkerframework.checker.nullness.qual; + public @interface NonNull {} + """ + ) + ) + .recipes( + new AddDependency("org.checkerframework", "checker-qual", "3.44.0", + null, null, null, "main.java.checkerframework..*", null, null, null, null, + true), + new ChangePackage("main.java.checkerframework", "org.checkerframework", true) + ), + mavenProject("parent", + pomXml( + """ + + com.mycompany.app + parent + 1 + + child + + + + + com.google.guava + guava + 31.1-jre + + + + """ + ), + mavenProject("child", + srcTestJava( + java( + """ + import main.java.checkerframework.checker.nullness.qual.NonNull; + class Foo {} + """, + """ + import org.checkerframework.checker.nullness.qual.NonNull; + class Foo {} + """ + ) + ), + pomXml( + """ + + + com.mycompany.app + parent + 1 + ../pom.xml + + child + + + com.google.guava + guava + 31.1-jre + test + + + + """ + ) + ) + ) + ); + } + private AddDependency addDependency(@SuppressWarnings("SameParameterValue") String gav) { return addDependency(gav, null, null, null); } diff --git a/rewrite-maven/src/test/java/org/openrewrite/maven/MavenParserTest.java b/rewrite-maven/src/test/java/org/openrewrite/maven/MavenParserTest.java index 3a6cb276ec8..44e1d67106c 100644 --- a/rewrite-maven/src/test/java/org/openrewrite/maven/MavenParserTest.java +++ b/rewrite-maven/src/test/java/org/openrewrite/maven/MavenParserTest.java @@ -3202,4 +3202,62 @@ void multiModulePropertyVersionShouldAddModules() { ) ); } + + @Test + void childDependencyDefinitionShouldTakePrecedence() { + rewriteRun( + mavenProject("parent", + pomXml( + """ + + com.mycompany.app + parent + 1 + + child + + + + com.google.guava + guava + 31.1-jre + + + + """ + ), + mavenProject("child", + pomXml( + """ + + + com.mycompany.app + parent + 1 + ../pom.xml + + child + + + com.google.guava + guava + 31.1-jre + test + + + + """, + spec -> spec.afterRecipe(pomXml -> { + MavenResolutionResult res = pomXml.getMarkers().findFirst(MavenResolutionResult.class).orElseThrow(); + assertThat(res.getDependencies().get(Scope.Compile)).isEmpty(); + assertThat(res.getDependencies().get(Scope.Runtime)).isEmpty(); + assertThat(res.getDependencies().get(Scope.Provided)).isEmpty(); + assertThat(res.getDependencies().get(Scope.Test)).isNotEmpty().anyMatch(dep -> dep.getGroupId().equals("com.google.guava") && dep.getArtifactId().equals("guava")); + } + ) + ) + ) + ) + ); + } }