Skip to content

Commit f47e540

Browse files
ravig-kantfabapp2
authored andcommitted
Remove spring managed dependency with version consideration (#602)
1 parent 2713377 commit f47e540

File tree

5 files changed

+208
-0
lines changed

5 files changed

+208
-0
lines changed

components/sbm-core/src/main/java/org/springframework/sbm/build/api/Dependency.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@
1717

1818
import io.micrometer.core.lang.Nullable;
1919
import lombok.*;
20+
import org.openrewrite.semver.LatestRelease;
2021

2122
import javax.validation.constraints.NotNull;
2223
import java.util.ArrayList;
24+
import java.util.Comparator;
2325
import java.util.List;
2426

2527
@Getter
@@ -66,6 +68,15 @@ public String toString() {
6668
"</dependency>";
6769
}
6870

71+
public boolean isRecentThen(Dependency that){
72+
return this.equals(that) && comparator().compare(this, that) >= 0;
73+
}
74+
75+
private Comparator<Dependency> comparator(){
76+
LatestRelease latestRelease = new LatestRelease(null);
77+
return Comparator.comparing(Dependency::getVersion, latestRelease::compare);
78+
}
79+
6980
private String exclusionString() {
7081
if (exclusions.isEmpty()) {
7182
return "";
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package org.springframework.sbm.build.api;
2+
3+
import org.openrewrite.maven.internal.MavenPomDownloader;
4+
import org.openrewrite.maven.tree.GroupArtifactVersion;
5+
import org.openrewrite.maven.tree.MavenRepository;
6+
import org.springframework.sbm.openrewrite.RewriteExecutionContext;
7+
8+
import java.util.Collections;
9+
import java.util.HashMap;
10+
import java.util.List;
11+
import java.util.Map;
12+
import java.util.stream.Stream;
13+
14+
/**
15+
* This class holds all the dependencies included in a spring artifact
16+
*/
17+
public class SpringManagedDependencies {
18+
19+
private static List<MavenRepository> SPRING_REPOSITORIES = List.of(
20+
new MavenRepository("spring-release", "https://repo.spring.io/release", true, false, null, null)
21+
);
22+
23+
private List<org.openrewrite.maven.tree.Dependency> dependencies;
24+
private static Map<GroupArtifactVersion, SpringManagedDependencies> INSTANCES = new HashMap<>();
25+
26+
public static SpringManagedDependencies by(String groupId, String artifact, String version){
27+
final GroupArtifactVersion groupArtifactVersion =
28+
new GroupArtifactVersion(groupId, artifact, version);
29+
30+
INSTANCES.computeIfAbsent(groupArtifactVersion, SpringManagedDependencies::new);
31+
return INSTANCES.get(groupArtifactVersion);
32+
}
33+
34+
private SpringManagedDependencies(GroupArtifactVersion groupArtifactVersion){
35+
dependencies = new MavenPomDownloader(Collections.emptyMap(), new RewriteExecutionContext())
36+
.download(groupArtifactVersion, null, null, SPRING_REPOSITORIES)
37+
.getDependencies();
38+
}
39+
40+
public Stream<Dependency> stream(){
41+
return dependencies.stream()
42+
.map(d -> Dependency.builder()
43+
.groupId(d.getGroupId())
44+
.artifactId(d.getArtifactId())
45+
.version(d.getVersion())
46+
.build()
47+
);
48+
}
49+
50+
51+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package org.springframework.sbm.build.migration.actions;
2+
3+
import org.springframework.sbm.build.api.Dependency;
4+
import org.springframework.sbm.build.api.SpringManagedDependencies;
5+
import org.springframework.sbm.engine.context.ProjectContext;
6+
import org.springframework.sbm.engine.recipe.AbstractAction;
7+
8+
import java.util.List;
9+
import java.util.function.Predicate;
10+
import java.util.stream.Collectors;
11+
12+
import static org.openrewrite.maven.tree.Scope.Compile;
13+
14+
/**
15+
* The action removes the dependencies directly managed by Spring from the project dependencies
16+
* Add this action at the end of recipe so that any spring artifact inclusions as part of the
17+
* other actions are also included while removing the dependencies.
18+
*/
19+
public class RemoveManagedDependencies extends AbstractAction {
20+
21+
@Override
22+
public void apply(ProjectContext context) {
23+
//FIXME handle multi-module projects
24+
final List<Dependency> springManagedDependencies = context.getBuildFile()
25+
.getDeclaredDependencies(Compile)
26+
.stream()
27+
.filter(this::isSpringFrameworkDependency)
28+
.map(d -> SpringManagedDependencies.by(d.getGroupId(),d.getArtifactId(),d.getVersion()))
29+
.flatMap(SpringManagedDependencies::stream)
30+
.distinct()
31+
.collect(Collectors.toList());
32+
33+
Predicate<Dependency> isAlreadyManagedBySpring = d -> springManagedDependencies
34+
.stream()
35+
.filter(d::equals)
36+
.anyMatch(s -> s.isRecentThen(d));
37+
38+
final List<Dependency> dependenciesToBeRemoved = context.getBuildFile()
39+
.getDeclaredDependencies(Compile)
40+
.stream()
41+
.filter(isAlreadyManagedBySpring)
42+
.collect(Collectors.toList());
43+
44+
RemoveDependencies removeDependenciesAction = new RemoveDependencies();
45+
removeDependenciesAction.setDependencies(dependenciesToBeRemoved);
46+
removeDependenciesAction.apply(context);
47+
}
48+
49+
private boolean isSpringFrameworkDependency(Dependency dependency){
50+
return dependency.getGroupId().startsWith("org.springframework");
51+
}
52+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package org.springframework.sbm.build.api;
2+
3+
import org.junit.jupiter.api.Test;
4+
import static org.assertj.core.api.Assertions.assertThat;
5+
6+
public class SpringManagedDependenciesTest {
7+
8+
@Test
9+
public void pullBootStarter274Dependencies_expectJakartaAnnotationDependency(){
10+
String jakartaCoordinates = "jakarta.annotation:jakarta.annotation-api:1.3.5";
11+
12+
assertThat( SpringManagedDependencies.by("org.springframework.boot", "spring-boot-starter", "2.7.4")
13+
.stream()
14+
.map(Dependency::getCoordinates)
15+
.anyMatch(jakartaCoordinates::equals)
16+
).isTrue();
17+
}
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package org.springframework.sbm.build.migration.actions;
2+
3+
import org.junit.jupiter.api.Test;
4+
import org.openrewrite.semver.LatestRelease;
5+
import org.springframework.sbm.build.api.Dependency;
6+
import org.springframework.sbm.engine.context.ProjectContext;
7+
import org.springframework.sbm.project.resource.TestProjectContext;
8+
9+
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
10+
11+
public class RemoveManagedDependenciesTest {
12+
13+
@Test
14+
public void givenProjectWithManagedDependency_removeSpringManagedDependencies_expectHibernateDependencyRemoved(){
15+
16+
LatestRelease latestRelease = new LatestRelease(null);
17+
System.out.println(latestRelease.compare(null, "5.6.11.Final", "5.6.11.Final"));
18+
19+
final String hibernateCoordinates = "org.hibernate:hibernate-core:5.6.11.Final";
20+
final String springBootDataJpaCoordinates = "org.springframework.boot:spring-boot-starter-data-jpa:2.7.4";
21+
22+
final ProjectContext projectContext = TestProjectContext.buildProjectContext()
23+
.withBuildFileHavingDependencies(hibernateCoordinates, springBootDataJpaCoordinates)
24+
.build();
25+
26+
RemoveManagedDependencies removeManagedDependencies = new RemoveManagedDependencies();
27+
removeManagedDependencies.apply(projectContext);
28+
29+
assertThat(projectContext.getBuildFile()
30+
.getDeclaredDependencies()
31+
.stream()
32+
.map(Dependency::getCoordinates)
33+
.anyMatch(hibernateCoordinates::equals)
34+
).isFalse();
35+
}
36+
37+
@Test
38+
public void givenProjectWithLowerVersionedManagedDependency_removeSpringManagedDependencies_expectDependencyRemoved(){
39+
final String hibernateCoordinates = "org.hibernate:hibernate-core:5.3.2.Final";
40+
final String springBootDataJpaCoordinates = "org.springframework.boot:spring-boot-starter-data-jpa:2.7.4";
41+
42+
final ProjectContext projectContext = TestProjectContext.buildProjectContext()
43+
.withBuildFileHavingDependencies(hibernateCoordinates, springBootDataJpaCoordinates)
44+
.build();
45+
46+
RemoveManagedDependencies removeManagedDependencies = new RemoveManagedDependencies();
47+
removeManagedDependencies.apply(projectContext);
48+
49+
assertThat(projectContext.getBuildFile()
50+
.getDeclaredDependencies()
51+
.stream()
52+
.map(Dependency::getCoordinates)
53+
.anyMatch(hibernateCoordinates::equals)
54+
).isFalse();
55+
}
56+
57+
@Test
58+
public void givenProjectWithHigherVersionedManagedDependency_removeSpringManagedDependencies_expectDependencyRemoved(){
59+
final String hibernateCoordinates = "org.hibernate:hibernate-core:5.12.2.Final";
60+
final String springBootDataJpaCoordinates = "org.springframework.boot:spring-boot-starter-data-jpa:2.7.4";
61+
62+
final ProjectContext projectContext = TestProjectContext.buildProjectContext()
63+
.withBuildFileHavingDependencies(hibernateCoordinates, springBootDataJpaCoordinates)
64+
.build();
65+
66+
RemoveManagedDependencies removeManagedDependencies = new RemoveManagedDependencies();
67+
removeManagedDependencies.apply(projectContext);
68+
69+
assertThat(projectContext.getBuildFile()
70+
.getDeclaredDependencies()
71+
.stream()
72+
.map(Dependency::getCoordinates)
73+
.anyMatch(hibernateCoordinates::equals)
74+
).isTrue();
75+
}
76+
}

0 commit comments

Comments
 (0)