1616
1717package org .openrewrite .maven .spring ;
1818
19- import com .fasterxml .jackson .annotation .JsonCreator ;
20- import com .fasterxml .jackson .annotation .JsonProperty ;
19+ import lombok .Data ;
2120import lombok .EqualsAndHashCode ;
21+ import lombok .Value ;
2222import org .openrewrite .*;
23- import org .openrewrite .groovy .tree .G ;
24- import org .openrewrite .internal .lang .NonNull ;
23+ import org .openrewrite .gradle .marker .GradleProject ;
2524import org .openrewrite .internal .lang .Nullable ;
25+ import org .openrewrite .java .dependencies .UpgradeDependencyVersion ;
2626import org .openrewrite .marker .SearchResult ;
2727import org .openrewrite .maven .MavenDownloadingException ;
2828import org .openrewrite .maven .MavenIsoVisitor ;
3333
3434import java .util .*;
3535
36+ import static java .util .Collections .emptyList ;
3637import static java .util .Collections .emptyMap ;
3738
39+ @ Value
3840@ EqualsAndHashCode (callSuper = false )
39- public class UpgradeExplicitSpringBootDependencies extends Recipe {
41+ public class UpgradeExplicitSpringBootDependencies extends ScanningRecipe < UpgradeExplicitSpringBootDependencies . Accumulator > {
4042
4143 private static final String SPRINGBOOT_GROUP = "org.springframework.boot" ;
4244 private static final String SPRING_BOOT_DEPENDENCIES = "spring-boot-dependencies" ;
4345
44- private transient final Map <String , String > springBootDependenciesMap = new HashMap <>();
45-
46- @ Option (displayName = "From Spring Version" ,
46+ @ Option (displayName = "From Spring version" ,
4747 description = "XRage pattern for spring version used to limit which projects should be updated" ,
4848 example = " 2.7.+" )
49- private final String fromVersion ;
49+ String fromVersion ;
5050
51- @ Option (displayName = "To Spring Version " ,
51+ @ Option (displayName = "To Spring version " ,
5252 description = "Upgrade version of `org.springframework.boot`" ,
5353 example = "3.0.0-M3" )
54- private final String toVersion ;
55-
56- @ JsonCreator
57- public UpgradeExplicitSpringBootDependencies (@ JsonProperty ("fromVersion" ) String fromVersion , @ JsonProperty ("toVersion" ) String toVersion ) {
58- this .fromVersion = fromVersion ;
59- this .toVersion = toVersion ;
60- }
54+ String toVersion ;
6155
6256 @ Override
6357 public String getDisplayName () {
64- return "Upgrade un-managed spring project dependencies" ;
58+ return "Upgrade Spring dependencies" ;
6559 }
6660
6761 @ Override
6862 public String getDescription () {
69- return "Upgrades un-managed spring-boot project dependencies according to the specified spring-boot version." ;
63+ return "Upgrades dependencies according to the specified version of spring boot. " +
64+ "Spring boot has many direct and transitive dependencies. When a module has an explicit dependency on " +
65+ "one of these it may also need to be upgraded to match the version used by spring boot." ;
66+ }
67+
68+ @ Data
69+ public static class Accumulator {
70+ UpgradeDependencyVersion .Accumulator udvAcc = new UpgradeDependencyVersion .Accumulator (
71+ new org .openrewrite .maven .UpgradeDependencyVersion .Accumulator (),
72+ new org .openrewrite .gradle .UpgradeDependencyVersion .DependencyVersionState ()
73+ );
74+ List <MavenRepository > repositories = new ArrayList <>();
75+ Map <String , String > springBootDependenciesMap = new HashMap <>();
76+ @ Nullable
77+ MavenDownloadingException mavenDownloadingException = null ;
7078 }
7179
7280 private TreeVisitor <?, ExecutionContext > precondition () {
@@ -78,40 +86,113 @@ public Xml.Tag visitTag(Xml.Tag tag, ExecutionContext ctx) {
7886 ResolvedManagedDependency managedDependency = findManagedDependency (resultTag );
7987 if (managedDependency != null && managedDependency .getGroupId ().equals (SPRINGBOOT_GROUP )
8088 && satisfiesOldVersionPattern (managedDependency .getVersion ())) {
81- return applyThisRecipe (resultTag );
89+ return SearchResult . found (resultTag );
8290 }
8391 }
8492
8593 if (isDependencyTag ()) {
8694 ResolvedDependency dependency = findDependency (resultTag );
8795 if ((dependency != null ) && dependency .getGroupId ().equals (SPRINGBOOT_GROUP )
8896 && satisfiesOldVersionPattern (dependency .getVersion ())) {
89- return applyThisRecipe (resultTag );
97+ return SearchResult . found (resultTag );
9098 }
9199 }
92100 return resultTag ;
93101 }
94102
95- @ NonNull
96- private Xml .Tag applyThisRecipe (Xml .Tag resultTag ) {
97- return resultTag .withMarkers (resultTag .getMarkers ().addIfAbsent (new SearchResult (UUID .randomUUID (), "SpringBoot dependency" )));
98- }
99-
100103 private boolean satisfiesOldVersionPattern (@ Nullable String version ) {
101104 return version != null && XRange .build (fromVersion , version ).isValid ();
102105 }
103106 };
104107 }
105108
106109 @ Override
107- public TreeVisitor <?, ExecutionContext > getVisitor () {
110+ public Accumulator getInitialValue (ExecutionContext ctx ) {
111+ return new Accumulator ();
112+ }
113+
114+ @ Override
115+ public TreeVisitor <?, ExecutionContext > getScanner (Accumulator acc ) {
116+ //noinspection NullableProblems
117+ return new TreeVisitor <Tree , ExecutionContext >() {
118+ @ Override
119+ public Tree visit (Tree tree , ExecutionContext ctx ) {
120+ TreeVisitor <?, ExecutionContext > udvScanner = new UpgradeDependencyVersion ("" , "" , "" , null , null , null )
121+ .getScanner (acc .getUdvAcc ());
122+ if (udvScanner .isAcceptable ((SourceFile ) tree , ctx )) {
123+ udvScanner .visit (tree , ctx );
124+ }
125+
126+ Optional <GradleProject > maybeGp = tree .getMarkers ()
127+ .findFirst (GradleProject .class );
128+ if (maybeGp .isPresent ()) {
129+ GradleProject gp = maybeGp .get ();
130+ acc .repositories .addAll (gp .getMavenRepositories ());
131+ }
132+ Optional <MavenResolutionResult > maybeMrr = tree .getMarkers ()
133+ .findFirst (MavenResolutionResult .class );
134+ if (maybeMrr .isPresent ()) {
135+ MavenResolutionResult mrr = maybeMrr .get ();
136+ acc .repositories .addAll (mrr .getPom ().getRepositories ());
137+ }
138+
139+ return tree ;
140+ }
141+ };
142+ }
143+
144+ @ Override
145+ public Collection <? extends SourceFile > generate (Accumulator acc , Collection <SourceFile > generatedInThisCycle , ExecutionContext ctx ) {
146+ List <MavenRepository > repositories = acc .getRepositories ();
147+ repositories .add (MavenRepository .builder ()
148+ .id ("repository.spring.milestone" )
149+ .uri ("https://repo.spring.io/milestone" )
150+ .releases (true )
151+ .snapshots (true )
152+ .build ());
153+ repositories .add (MavenRepository .builder ()
154+ .id ("spring-snapshot" )
155+ .uri ("https://repo.spring.io/snapshot" )
156+ .releases (false )
157+ .snapshots (true )
158+ .build ());
159+ repositories .add (MavenRepository .builder ()
160+ .id ("spring-release" )
161+ .uri ("https://repo.spring.io/release" )
162+ .releases (true )
163+ .snapshots (false )
164+ .build ());
165+
166+ MavenPomDownloader downloader = new MavenPomDownloader (emptyMap (), ctx );
167+ GroupArtifactVersion gav = new GroupArtifactVersion (SPRINGBOOT_GROUP , SPRING_BOOT_DEPENDENCIES , toVersion );
168+ String relativePath = "" ;
169+
170+ try {
171+ Pom pom = downloader .download (gav , relativePath , null , repositories );
172+ ResolvedPom resolvedPom = pom .resolve (emptyList (), downloader , repositories , ctx );
173+ List <ResolvedManagedDependency > dependencyManagement = resolvedPom .getDependencyManagement ();
174+ dependencyManagement
175+ .stream ()
176+ .filter (d -> d .getVersion () != null )
177+ .forEach (d -> acc .getSpringBootDependenciesMap ().put (d .getGroupId () + ":" + d .getArtifactId ().toLowerCase (), d .getVersion ()));
178+ } catch (MavenDownloadingException e ) {
179+ acc .mavenDownloadingException = e ;
180+ }
181+ return emptyList ();
182+ }
183+
184+ @ Override
185+ public Collection <? extends SourceFile > generate (Accumulator acc , ExecutionContext ctx ) {
186+ return super .generate (acc , ctx );
187+ }
188+
189+ @ Override
190+ public TreeVisitor <?, ExecutionContext > getVisitor (Accumulator acc ) {
108191 return Preconditions .check (precondition (), new MavenIsoVisitor <ExecutionContext >() {
109192 @ Override
110193 public Xml .Document visitDocument (Xml .Document document , ExecutionContext ctx ) {
111- try {
112- buildDependencyMap (ctx );
113- } catch (MavenDownloadingException e ) {
114- return e .warn (document );
194+ if (acc .mavenDownloadingException != null ) {
195+ return acc .mavenDownloadingException .warn (document );
115196 }
116197 return super .visitDocument (document , ctx );
117198 }
@@ -122,71 +203,29 @@ public Xml.Tag visitTag(Xml.Tag tag, ExecutionContext ctx) {
122203 if (isManagedDependencyTag ()) {
123204 ResolvedManagedDependency managedDependency = findManagedDependency (resultTag );
124205 if (managedDependency != null ) {
125- mayBeUpdateVersion (managedDependency .getGroupId (), managedDependency .getArtifactId (), resultTag );
206+ mayBeUpdateVersion (acc , managedDependency .getGroupId (), managedDependency .getArtifactId (), resultTag );
126207 }
127208 }
128209 if (isDependencyTag ()) {
129210 ResolvedDependency dependency = findDependency (resultTag );
130211 if (dependency != null ) {
131- mayBeUpdateVersion (dependency .getGroupId (), dependency .getArtifactId (), resultTag );
212+ mayBeUpdateVersion (acc , dependency .getGroupId (), dependency .getArtifactId (), resultTag );
132213 }
133214 }
134215 return resultTag ;
135216 }
136217
137- private void mayBeUpdateVersion (String groupId , String artifactId , Xml .Tag tag ) {
138- String dependencyVersion = springBootDependenciesMap .get (groupId + ":" + artifactId );
218+ private void mayBeUpdateVersion (Accumulator acc , String groupId , String artifactId , Xml .Tag tag ) {
219+ String dependencyVersion = acc . springBootDependenciesMap .get (groupId + ":" + artifactId );
139220 if (dependencyVersion != null ) {
140221 Optional <Xml .Tag > version = tag .getChild ("version" );
141222 if (!version .isPresent () || !version .get ().getValue ().isPresent ()) {
142223 return ;
143224 }
144- // TODO: we could use the org.openrewrite.java.dependencies.UpgradeDependencyVersion if we implement there a getVisitor with a similar logic than here,
145- // but right now it's just a list of recipes, and the getVisitor is the default from Recipe and does nothing
146- SourceFile sourceFile = getCursor ().firstEnclosing (SourceFile .class );
147- if (sourceFile instanceof Xml .Document ) {
148- doAfterVisit (new org .openrewrite .maven .UpgradeDependencyVersion (groupId , artifactId , dependencyVersion , null , null , null ).getVisitor ());
149- } else if (sourceFile instanceof G .CompilationUnit ) {
150- doAfterVisit (new org .openrewrite .gradle .UpgradeDependencyVersion (groupId , artifactId , dependencyVersion , null ).getVisitor ());
151- }
225+ doAfterVisit (new org .openrewrite .java .dependencies .UpgradeDependencyVersion (groupId , artifactId , dependencyVersion , null , true , null )
226+ .getVisitor (acc .getUdvAcc ()));
152227 }
153228 }
154-
155- private void buildDependencyMap (ExecutionContext ctx ) throws MavenDownloadingException {
156- if (springBootDependenciesMap .isEmpty ()) {
157- MavenPomDownloader downloader = new MavenPomDownloader (emptyMap (), ctx ,
158- getResolutionResult ().getMavenSettings (), getResolutionResult ().getActiveProfiles ());
159- GroupArtifactVersion gav = new GroupArtifactVersion (SPRINGBOOT_GROUP , SPRING_BOOT_DEPENDENCIES , toVersion );
160- String relativePath = "" ;
161- List <MavenRepository > repositories = new ArrayList <>();
162- repositories .add (MavenRepository .builder ()
163- .id ("repository.spring.milestone" )
164- .uri ("https://repo.spring.io/milestone" )
165- .releases (true )
166- .snapshots (true )
167- .build ());
168- repositories .add (MavenRepository .builder ()
169- .id ("spring-snapshot" )
170- .uri ("https://repo.spring.io/snapshot" )
171- .releases (false )
172- .snapshots (true )
173- .build ());
174- repositories .add (MavenRepository .builder ()
175- .id ("spring-release" )
176- .uri ("https://repo.spring.io/release" )
177- .releases (true )
178- .snapshots (false )
179- .build ());
180- Pom pom = downloader .download (gav , relativePath , null , repositories );
181- ResolvedPom resolvedPom = pom .resolve (Collections .emptyList (), downloader , repositories , ctx );
182- List <ResolvedManagedDependency > dependencyManagement = resolvedPom .getDependencyManagement ();
183- dependencyManagement
184- .stream ()
185- .filter (d -> d .getVersion () != null )
186- .forEach (d -> springBootDependenciesMap .put (d .getGroupId () + ":" + d .getArtifactId ().toLowerCase (), d .getVersion ()));
187- }
188- }
189-
190229 });
191230 }
192231}
0 commit comments