From a4573484f9d583c94ccf5f2c184f096523458e67 Mon Sep 17 00:00:00 2001 From: lingenj Date: Fri, 4 Jul 2025 11:42:18 +0200 Subject: [PATCH 1/6] Keep `jakarta.annotation-api` dependency when moving to Jakarta with Spring Boot project and null annotations are used --- .../jakarta/HasNoJakartaNullAnnotations.java | 61 ++++++ .../META-INF/rewrite/jakarta-ee-9.yml | 1 + .../migrate/jakarta/JavaxToJakartaTest.java | 174 ++++++++++++++++++ 3 files changed, 236 insertions(+) create mode 100644 src/main/java/org/openrewrite/java/migrate/jakarta/HasNoJakartaNullAnnotations.java diff --git a/src/main/java/org/openrewrite/java/migrate/jakarta/HasNoJakartaNullAnnotations.java b/src/main/java/org/openrewrite/java/migrate/jakarta/HasNoJakartaNullAnnotations.java new file mode 100644 index 0000000000..78e9b56574 --- /dev/null +++ b/src/main/java/org/openrewrite/java/migrate/jakarta/HasNoJakartaNullAnnotations.java @@ -0,0 +1,61 @@ +package org.openrewrite.java.migrate.jakarta; + +import org.jspecify.annotations.Nullable; +import org.openrewrite.ExecutionContext; +import org.openrewrite.ScanningRecipe; +import org.openrewrite.Tree; +import org.openrewrite.TreeVisitor; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.search.FindAnnotations; +import org.openrewrite.java.tree.J; +import org.openrewrite.marker.SearchResult; + +import java.util.concurrent.atomic.AtomicBoolean; + +public class HasNoJakartaNullAnnotations extends ScanningRecipe { + @Override + public String getDisplayName() { + return "Project has no Jakarta null annotations"; + } + + @Override + public String getDescription() { + return "Search for @Nonnull and @Nullable annotations, mark all source as found if no annotations are found."; + } + + @Override + public AtomicBoolean getInitialValue(ExecutionContext ctx) { + return new AtomicBoolean(); + } + + @Override + public TreeVisitor getScanner(AtomicBoolean acc) { + return new JavaIsoVisitor() { + @Override + public J.CompilationUnit visitCompilationUnit(J.CompilationUnit cu, ExecutionContext ctx) { + J.CompilationUnit c = super.visitCompilationUnit(cu, ctx); + if (!acc.get()) { + if ((!FindAnnotations.find(c, "@jakarta.annotation.Nonnull", true).isEmpty()) || + (!FindAnnotations.find(c, "@jakarta.annotation.Nullable", true).isEmpty())) { + acc.set(true); + } + } + return cu; + } + }; + } + + @Override + public TreeVisitor getVisitor(AtomicBoolean acc) { + return new TreeVisitor() { + @Override + public Tree visit(@Nullable Tree tree, ExecutionContext ctx) { + assert tree != null; + if (!acc.get()) { + return SearchResult.found(tree, "Project has no Jakarta null annotations"); + } + return tree; + } + }; + } +} diff --git a/src/main/resources/META-INF/rewrite/jakarta-ee-9.yml b/src/main/resources/META-INF/rewrite/jakarta-ee-9.yml index f9783487b7..cda1f1b9ad 100644 --- a/src/main/resources/META-INF/rewrite/jakarta-ee-9.yml +++ b/src/main/resources/META-INF/rewrite/jakarta-ee-9.yml @@ -1083,6 +1083,7 @@ name: org.openrewrite.java.migrate.jakarta.RemoveJakartaAnnotationDependency displayName: Remove `jakarta.annotation-api` dependency when managed by Spring Boot description: Counteract the `jakarta.annotation-api` added by `org.openrewrite.java.migrate.javax.AddCommonAnnotationsDependencies` for Spring Boot applications. preconditions: + - org.openrewrite.java.migrate.jakarta.HasNoJakartaNullAnnotations - org.openrewrite.java.dependencies.DependencyInsight: groupIdPattern: org.springframework.boot artifactIdPattern: spring-boot-starter diff --git a/src/test/java/org/openrewrite/java/migrate/jakarta/JavaxToJakartaTest.java b/src/test/java/org/openrewrite/java/migrate/jakarta/JavaxToJakartaTest.java index 94b2f2fe17..1c60b1f489 100644 --- a/src/test/java/org/openrewrite/java/migrate/jakarta/JavaxToJakartaTest.java +++ b/src/test/java/org/openrewrite/java/migrate/jakarta/JavaxToJakartaTest.java @@ -60,6 +60,16 @@ public void foo() {} } """; + @Language("java") + private static final String jakartaAnnotation = + """ + package jakarta.annotation; + public @interface Nonnull { + } + public @interface Nullable { + } + """; + @Override public void defaults(RecipeSpec spec) { spec.recipe( @@ -574,6 +584,170 @@ public class TestApplication { ); } + @Test + void projectWithSpringBoot3StarterWebShouldNotRemoveJakartaDependencyWhenUsingNonnullAnnotation() { + rewriteRun( + spec -> spec.parser(JavaParser.fromJavaVersion().dependsOn(javaxServlet, jakartaAnnotation)), + mavenProject( + "Sample", + //language=xml + pomXml( + """ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.2.5 + + + com.example + demo + 0.0.1-SNAPSHOT + + + jakarta.annotation + jakarta.annotation-api + 1.3.5 + + + org.springframework.boot + spring-boot-starter-web + + + + """, + """ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.2.5 + + + com.example + demo + 0.0.1-SNAPSHOT + + + jakarta.annotation + jakarta.annotation-api + 2.0.0 + + + org.springframework.boot + spring-boot-starter-web + + + + """ + ), + srcMainJava( + //language=java + java( + """ + import jakarta.annotation.Nonnull; + + public class TestApplication { + @Nonnull + public String upperCase(@Nonnull String input) { + return input.toUpperCase(); + } + } + """ + ) + ) + ) + ); + } + + @Test + void projectWithSpringBoot3StarterWebShouldNotRemoveJakartaDependencyWhenUsingNullableAnnotation() { + rewriteRun( + spec -> spec.parser(JavaParser.fromJavaVersion().dependsOn(javaxServlet, jakartaAnnotation)), + mavenProject( + "Sample", + //language=xml + pomXml( + """ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.2.5 + + + com.example + demo + 0.0.1-SNAPSHOT + + + jakarta.annotation + jakarta.annotation-api + 1.3.5 + + + org.springframework.boot + spring-boot-starter-web + + + + """, + """ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.2.5 + + + com.example + demo + 0.0.1-SNAPSHOT + + + jakarta.annotation + jakarta.annotation-api + 2.0.0 + + + org.springframework.boot + spring-boot-starter-web + + + + """ + ), + srcMainJava( + //language=java + java( + """ + import jakarta.annotation.Nullable; + + public class TestApplication { + @Nullable + public String safeUpperCase(@Nullable String input) { + return input == null ? null : input.toUpperCase(); + } + } + """ + ) + ) + ) + ); + } + @Test void upgradeAnnotationApiFromV1ToV2() { rewriteRun( From 80f05962ae493d1f32145491c9b09c5ad11a72b1 Mon Sep 17 00:00:00 2001 From: lingenj Date: Fri, 4 Jul 2025 11:51:44 +0200 Subject: [PATCH 2/6] Add license --- .../jakarta/HasNoJakartaNullAnnotations.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main/java/org/openrewrite/java/migrate/jakarta/HasNoJakartaNullAnnotations.java b/src/main/java/org/openrewrite/java/migrate/jakarta/HasNoJakartaNullAnnotations.java index 78e9b56574..c8fdc14fc2 100644 --- a/src/main/java/org/openrewrite/java/migrate/jakarta/HasNoJakartaNullAnnotations.java +++ b/src/main/java/org/openrewrite/java/migrate/jakarta/HasNoJakartaNullAnnotations.java @@ -1,3 +1,18 @@ +/* + * Copyright 2025 the original author or authors. + *

+ * Licensed under the Moderne Source Available License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://docs.moderne.io/licensing/moderne-source-available-license + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.openrewrite.java.migrate.jakarta; import org.jspecify.annotations.Nullable; From 616ec2482d4aa3c9a33a2a17b9f78f7bf83184b0 Mon Sep 17 00:00:00 2001 From: Jacob van Lingen Date: Fri, 4 Jul 2025 12:01:57 +0200 Subject: [PATCH 3/6] Update src/test/java/org/openrewrite/java/migrate/jakarta/JavaxToJakartaTest.java Co-authored-by: Tim te Beek --- .../migrate/jakarta/JavaxToJakartaTest.java | 28 +++++-------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/src/test/java/org/openrewrite/java/migrate/jakarta/JavaxToJakartaTest.java b/src/test/java/org/openrewrite/java/migrate/jakarta/JavaxToJakartaTest.java index 1c60b1f489..9f80dea78f 100644 --- a/src/test/java/org/openrewrite/java/migrate/jakarta/JavaxToJakartaTest.java +++ b/src/test/java/org/openrewrite/java/migrate/jakarta/JavaxToJakartaTest.java @@ -452,9 +452,7 @@ void projectWithSpringBootStarterWeb() { //language=xml pomXml( """ - - + 4.0.0 org.springframework.boot @@ -521,9 +519,7 @@ void projectWithSpringBoot3StarterWebShouldRemoveJakartaDependency() { //language=xml pomXml( """ - - + 4.0.0 org.springframework.boot @@ -548,9 +544,7 @@ void projectWithSpringBoot3StarterWebShouldRemoveJakartaDependency() { """, """ - - + 4.0.0 org.springframework.boot @@ -593,9 +587,7 @@ void projectWithSpringBoot3StarterWebShouldNotRemoveJakartaDependencyWhenUsingNo //language=xml pomXml( """ - - + 4.0.0 org.springframework.boot @@ -620,9 +612,7 @@ void projectWithSpringBoot3StarterWebShouldNotRemoveJakartaDependencyWhenUsingNo """, """ - - + 4.0.0 org.springframework.boot @@ -675,9 +665,7 @@ void projectWithSpringBoot3StarterWebShouldNotRemoveJakartaDependencyWhenUsingNu //language=xml pomXml( """ - - + 4.0.0 org.springframework.boot @@ -702,9 +690,7 @@ void projectWithSpringBoot3StarterWebShouldNotRemoveJakartaDependencyWhenUsingNu """, """ - - + 4.0.0 org.springframework.boot From 5819247fd23f340570a857c83b4f9d75ce92898a Mon Sep 17 00:00:00 2001 From: lingenj Date: Fri, 4 Jul 2025 14:54:54 +0200 Subject: [PATCH 4/6] Implement multimodule solution --- .../jakarta/HasNoJakartaNullAnnotations.java | 47 ++++++----- .../migrate/jakarta/JavaxToJakartaTest.java | 83 +++++++++++++++++++ 2 files changed, 110 insertions(+), 20 deletions(-) diff --git a/src/main/java/org/openrewrite/java/migrate/jakarta/HasNoJakartaNullAnnotations.java b/src/main/java/org/openrewrite/java/migrate/jakarta/HasNoJakartaNullAnnotations.java index c8fdc14fc2..64b715b7de 100644 --- a/src/main/java/org/openrewrite/java/migrate/jakarta/HasNoJakartaNullAnnotations.java +++ b/src/main/java/org/openrewrite/java/migrate/jakarta/HasNoJakartaNullAnnotations.java @@ -15,19 +15,21 @@ */ package org.openrewrite.java.migrate.jakarta; +import lombok.Value; import org.jspecify.annotations.Nullable; import org.openrewrite.ExecutionContext; import org.openrewrite.ScanningRecipe; import org.openrewrite.Tree; import org.openrewrite.TreeVisitor; -import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.marker.JavaProject; import org.openrewrite.java.search.FindAnnotations; import org.openrewrite.java.tree.J; import org.openrewrite.marker.SearchResult; -import java.util.concurrent.atomic.AtomicBoolean; +import java.util.HashSet; +import java.util.Set; -public class HasNoJakartaNullAnnotations extends ScanningRecipe { +public class HasNoJakartaNullAnnotations extends ScanningRecipe { @Override public String getDisplayName() { return "Project has no Jakarta null annotations"; @@ -38,38 +40,43 @@ public String getDescription() { return "Search for @Nonnull and @Nullable annotations, mark all source as found if no annotations are found."; } + @Value + public static class Accumulator { + Set projectsWithDependency; + } + @Override - public AtomicBoolean getInitialValue(ExecutionContext ctx) { - return new AtomicBoolean(); + public Accumulator getInitialValue(ExecutionContext ctx) { + return new Accumulator(new HashSet<>()); } @Override - public TreeVisitor getScanner(AtomicBoolean acc) { - return new JavaIsoVisitor() { + public TreeVisitor getScanner(HasNoJakartaNullAnnotations.Accumulator acc) { + return new TreeVisitor() { @Override - public J.CompilationUnit visitCompilationUnit(J.CompilationUnit cu, ExecutionContext ctx) { - J.CompilationUnit c = super.visitCompilationUnit(cu, ctx); - if (!acc.get()) { - if ((!FindAnnotations.find(c, "@jakarta.annotation.Nonnull", true).isEmpty()) || - (!FindAnnotations.find(c, "@jakarta.annotation.Nullable", true).isEmpty())) { - acc.set(true); - } + public Tree visit(@Nullable Tree tree, ExecutionContext ctx) { + assert tree != null; + if (tree instanceof J) { + tree.getMarkers().findFirst(JavaProject.class) + .filter(__ ->!FindAnnotations.find((J) tree, "@jakarta.annotation.Nonnull", true).isEmpty() || + !FindAnnotations.find((J) tree, "@jakarta.annotation.Nullable", true).isEmpty()) + .ifPresent(it -> acc.getProjectsWithDependency().add(it)); } - return cu; + return tree; } }; } @Override - public TreeVisitor getVisitor(AtomicBoolean acc) { + public TreeVisitor getVisitor(HasNoJakartaNullAnnotations.Accumulator acc) { return new TreeVisitor() { @Override public Tree visit(@Nullable Tree tree, ExecutionContext ctx) { assert tree != null; - if (!acc.get()) { - return SearchResult.found(tree, "Project has no Jakarta null annotations"); - } - return tree; + return tree.getMarkers().findFirst(JavaProject.class) + .filter(it -> !acc.getProjectsWithDependency().contains(it)) + .map(__ -> SearchResult.found(tree, "Project has no Jakarta null annotations")) + .orElse(tree); } }; } diff --git a/src/test/java/org/openrewrite/java/migrate/jakarta/JavaxToJakartaTest.java b/src/test/java/org/openrewrite/java/migrate/jakarta/JavaxToJakartaTest.java index 9f80dea78f..f57b4f7f24 100644 --- a/src/test/java/org/openrewrite/java/migrate/jakarta/JavaxToJakartaTest.java +++ b/src/test/java/org/openrewrite/java/migrate/jakarta/JavaxToJakartaTest.java @@ -24,6 +24,9 @@ import org.openrewrite.test.RecipeSpec; import org.openrewrite.test.RewriteTest; +import static org.openrewrite.gradle.Assertions.buildGradle; +import static org.openrewrite.gradle.Assertions.settingsGradle; +import static org.openrewrite.gradle.toolingapi.Assertions.withToolingApi; import static org.openrewrite.java.Assertions.*; import static org.openrewrite.maven.Assertions.pomXml; import static org.openrewrite.xml.Assertions.xml; @@ -734,6 +737,86 @@ public String safeUpperCase(@Nullable String input) { ); } + @Test + void multiProjectWithSpringBoot3StarterWebShouldRemoveJakartaDependencyWhenUsingNullableAnnotationWhenApplicable() { + rewriteRun( + spec -> spec.beforeRecipe(withToolingApi()).parser(JavaParser.fromJavaVersion().dependsOn(javaxServlet, jakartaAnnotation)), + mavenProject("multi-project-build", + //language=groovy + settingsGradle(""" + include 'project-with-null-annotations' + include 'project-without-null-annotations' + """), + mavenProject("project-with-null-annotations", + //language=groovy + buildGradle( + """ + plugins { + id 'java' + } + + repositories { + mavenCentral() + } + + dependencies { + implementation 'jakarta.annotation:jakarta.annotation-api:1.3.5' + implementation 'org.springframework.boot:spring-boot-starter-web' + } + """, + """ + plugins { + id 'java' + } + + repositories { + mavenCentral() + } + + dependencies { + implementation 'jakarta.annotation:jakarta.annotation-api:2.0.0' + implementation 'org.springframework.boot:spring-boot-starter-web' + } + """ + ), + srcMainJava( + //language=java + java( + """ + import jakarta.annotation.Nullable; + + public class TestApplication { + @Nullable + public String safeUpperCase(@Nullable String input) { + return input == null ? null : input.toUpperCase(); + } + } + """ + ) + ) + ), + mavenProject("project-without-null-annotations", + //language=groovy + buildGradle( + """ + plugins { + id 'java' + } + + repositories { + mavenCentral() + } + + dependencies { + implementation 'org.springframework.boot:spring-boot-starter-web' + } + """ + ) + ) + ) + ); + } + @Test void upgradeAnnotationApiFromV1ToV2() { rewriteRun( From 3f4db748e7445286c70ffcfc28cc581def7862f3 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Mon, 7 Jul 2025 10:54:08 +0200 Subject: [PATCH 5/6] Stop looking through JavaProject after first annotation is found --- .../java/migrate/jakarta/HasNoJakartaNullAnnotations.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/openrewrite/java/migrate/jakarta/HasNoJakartaNullAnnotations.java b/src/main/java/org/openrewrite/java/migrate/jakarta/HasNoJakartaNullAnnotations.java index 64b715b7de..466a4463ab 100644 --- a/src/main/java/org/openrewrite/java/migrate/jakarta/HasNoJakartaNullAnnotations.java +++ b/src/main/java/org/openrewrite/java/migrate/jakarta/HasNoJakartaNullAnnotations.java @@ -28,6 +28,7 @@ import java.util.HashSet; import java.util.Set; +import java.util.function.Predicate; public class HasNoJakartaNullAnnotations extends ScanningRecipe { @Override @@ -37,7 +38,7 @@ public String getDisplayName() { @Override public String getDescription() { - return "Search for @Nonnull and @Nullable annotations, mark all source as found if no annotations are found."; + return "Search for `@Nonnull` and `@Nullable` annotations, mark all source as found if no annotations are found."; } @Value @@ -58,6 +59,7 @@ public Tree visit(@Nullable Tree tree, ExecutionContext ctx) { assert tree != null; if (tree instanceof J) { tree.getMarkers().findFirst(JavaProject.class) + .filter(jp -> !acc.getProjectsWithDependency().contains(jp)) .filter(__ ->!FindAnnotations.find((J) tree, "@jakarta.annotation.Nonnull", true).isEmpty() || !FindAnnotations.find((J) tree, "@jakarta.annotation.Nullable", true).isEmpty()) .ifPresent(it -> acc.getProjectsWithDependency().add(it)); From 48dd573fb810be56b31abe6a256c2821c07634eb Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Mon, 7 Jul 2025 11:26:20 +0200 Subject: [PATCH 6/6] Use `preVisit` to limit traversal, and find any Jakarta annotations --- ...ions.java => HasNoJakartaAnnotations.java} | 28 +++++++++---------- .../META-INF/rewrite/jakarta-ee-9.yml | 2 +- 2 files changed, 14 insertions(+), 16 deletions(-) rename src/main/java/org/openrewrite/java/migrate/jakarta/{HasNoJakartaNullAnnotations.java => HasNoJakartaAnnotations.java} (69%) diff --git a/src/main/java/org/openrewrite/java/migrate/jakarta/HasNoJakartaNullAnnotations.java b/src/main/java/org/openrewrite/java/migrate/jakarta/HasNoJakartaAnnotations.java similarity index 69% rename from src/main/java/org/openrewrite/java/migrate/jakarta/HasNoJakartaNullAnnotations.java rename to src/main/java/org/openrewrite/java/migrate/jakarta/HasNoJakartaAnnotations.java index 466a4463ab..528200eaa9 100644 --- a/src/main/java/org/openrewrite/java/migrate/jakarta/HasNoJakartaNullAnnotations.java +++ b/src/main/java/org/openrewrite/java/migrate/jakarta/HasNoJakartaAnnotations.java @@ -16,7 +16,6 @@ package org.openrewrite.java.migrate.jakarta; import lombok.Value; -import org.jspecify.annotations.Nullable; import org.openrewrite.ExecutionContext; import org.openrewrite.ScanningRecipe; import org.openrewrite.Tree; @@ -28,17 +27,17 @@ import java.util.HashSet; import java.util.Set; -import java.util.function.Predicate; -public class HasNoJakartaNullAnnotations extends ScanningRecipe { +public class HasNoJakartaAnnotations extends ScanningRecipe { @Override public String getDisplayName() { - return "Project has no Jakarta null annotations"; + return "Project has no Jakarta annotations"; } @Override public String getDescription() { - return "Search for `@Nonnull` and `@Nullable` annotations, mark all source as found if no annotations are found."; + return "Mark all source as found per `JavaProject` where no Jakarta annotations are found. " + + "This is useful mostly as a precondition for recipes that require Jakarta annotations to be present"; } @Value @@ -52,17 +51,16 @@ public Accumulator getInitialValue(ExecutionContext ctx) { } @Override - public TreeVisitor getScanner(HasNoJakartaNullAnnotations.Accumulator acc) { + public TreeVisitor getScanner(HasNoJakartaAnnotations.Accumulator acc) { return new TreeVisitor() { @Override - public Tree visit(@Nullable Tree tree, ExecutionContext ctx) { - assert tree != null; + public Tree preVisit(Tree tree, ExecutionContext ctx) { + stopAfterPreVisit(); if (tree instanceof J) { tree.getMarkers().findFirst(JavaProject.class) .filter(jp -> !acc.getProjectsWithDependency().contains(jp)) - .filter(__ ->!FindAnnotations.find((J) tree, "@jakarta.annotation.Nonnull", true).isEmpty() || - !FindAnnotations.find((J) tree, "@jakarta.annotation.Nullable", true).isEmpty()) - .ifPresent(it -> acc.getProjectsWithDependency().add(it)); + .filter(jp -> !FindAnnotations.find((J) tree, "@jakarta.annotation.*", true).isEmpty()) + .ifPresent(jp -> acc.getProjectsWithDependency().add(jp)); } return tree; } @@ -70,14 +68,14 @@ public Tree visit(@Nullable Tree tree, ExecutionContext ctx) { } @Override - public TreeVisitor getVisitor(HasNoJakartaNullAnnotations.Accumulator acc) { + public TreeVisitor getVisitor(HasNoJakartaAnnotations.Accumulator acc) { return new TreeVisitor() { @Override - public Tree visit(@Nullable Tree tree, ExecutionContext ctx) { - assert tree != null; + public Tree preVisit(Tree tree, ExecutionContext ctx) { + stopAfterPreVisit(); return tree.getMarkers().findFirst(JavaProject.class) .filter(it -> !acc.getProjectsWithDependency().contains(it)) - .map(__ -> SearchResult.found(tree, "Project has no Jakarta null annotations")) + .map(__ -> SearchResult.found(tree, "Project has no Jakarta annotations")) .orElse(tree); } }; diff --git a/src/main/resources/META-INF/rewrite/jakarta-ee-9.yml b/src/main/resources/META-INF/rewrite/jakarta-ee-9.yml index cda1f1b9ad..69d3657524 100644 --- a/src/main/resources/META-INF/rewrite/jakarta-ee-9.yml +++ b/src/main/resources/META-INF/rewrite/jakarta-ee-9.yml @@ -1083,7 +1083,7 @@ name: org.openrewrite.java.migrate.jakarta.RemoveJakartaAnnotationDependency displayName: Remove `jakarta.annotation-api` dependency when managed by Spring Boot description: Counteract the `jakarta.annotation-api` added by `org.openrewrite.java.migrate.javax.AddCommonAnnotationsDependencies` for Spring Boot applications. preconditions: - - org.openrewrite.java.migrate.jakarta.HasNoJakartaNullAnnotations + - org.openrewrite.java.migrate.jakarta.HasNoJakartaAnnotations - org.openrewrite.java.dependencies.DependencyInsight: groupIdPattern: org.springframework.boot artifactIdPattern: spring-boot-starter