2424import org .openrewrite .test .RecipeSpec ;
2525import org .openrewrite .test .RewriteTest ;
2626
27+ import static org .openrewrite .gradle .Assertions .buildGradle ;
28+ import static org .openrewrite .gradle .Assertions .settingsGradle ;
29+ import static org .openrewrite .gradle .toolingapi .Assertions .withToolingApi ;
2730import static org .openrewrite .java .Assertions .*;
2831import static org .openrewrite .maven .Assertions .pomXml ;
2932import static org .openrewrite .xml .Assertions .xml ;
@@ -60,6 +63,16 @@ public void foo() {}
6063 }
6164 """ ;
6265
66+ @ Language ("java" )
67+ private static final String jakartaAnnotation =
68+ """
69+ package jakarta.annotation;
70+ public @interface Nonnull {
71+ }
72+ public @interface Nullable {
73+ }
74+ """ ;
75+
6376 @ Override
6477 public void defaults (RecipeSpec spec ) {
6578 spec .recipe (
@@ -442,9 +455,7 @@ void projectWithSpringBootStarterWeb() {
442455 //language=xml
443456 pomXml (
444457 """
445- <?xml version="1.0" encoding="UTF-8"?>
446- <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
447- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
458+ <project>
448459 <modelVersion>4.0.0</modelVersion>
449460 <parent>
450461 <groupId>org.springframework.boot</groupId>
@@ -511,9 +522,7 @@ void projectWithSpringBoot3StarterWebShouldRemoveJakartaDependency() {
511522 //language=xml
512523 pomXml (
513524 """
514- <?xml version="1.0" encoding="UTF-8"?>
515- <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
516- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
525+ <project>
517526 <modelVersion>4.0.0</modelVersion>
518527 <parent>
519528 <groupId>org.springframework.boot</groupId>
@@ -538,9 +547,7 @@ void projectWithSpringBoot3StarterWebShouldRemoveJakartaDependency() {
538547 </project>
539548 """ ,
540549 """
541- <?xml version="1.0" encoding="UTF-8"?>
542- <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
543- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
550+ <project>
544551 <modelVersion>4.0.0</modelVersion>
545552 <parent>
546553 <groupId>org.springframework.boot</groupId>
@@ -574,6 +581,242 @@ public class TestApplication {
574581 );
575582 }
576583
584+ @ Test
585+ void projectWithSpringBoot3StarterWebShouldNotRemoveJakartaDependencyWhenUsingNonnullAnnotation () {
586+ rewriteRun (
587+ spec -> spec .parser (JavaParser .fromJavaVersion ().dependsOn (javaxServlet , jakartaAnnotation )),
588+ mavenProject (
589+ "Sample" ,
590+ //language=xml
591+ pomXml (
592+ """
593+ <project>
594+ <modelVersion>4.0.0</modelVersion>
595+ <parent>
596+ <groupId>org.springframework.boot</groupId>
597+ <artifactId>spring-boot-starter-parent</artifactId>
598+ <version>3.2.5</version>
599+ <relativePath/> <!-- lookup parent from repository -->
600+ </parent>
601+ <groupId>com.example</groupId>
602+ <artifactId>demo</artifactId>
603+ <version>0.0.1-SNAPSHOT</version>
604+ <dependencies>
605+ <dependency>
606+ <groupId>jakarta.annotation</groupId>
607+ <artifactId>jakarta.annotation-api</artifactId>
608+ <version>1.3.5</version>
609+ </dependency>
610+ <dependency>
611+ <groupId>org.springframework.boot</groupId>
612+ <artifactId>spring-boot-starter-web</artifactId>
613+ </dependency>
614+ </dependencies>
615+ </project>
616+ """ ,
617+ """
618+ <project>
619+ <modelVersion>4.0.0</modelVersion>
620+ <parent>
621+ <groupId>org.springframework.boot</groupId>
622+ <artifactId>spring-boot-starter-parent</artifactId>
623+ <version>3.2.5</version>
624+ <relativePath/> <!-- lookup parent from repository -->
625+ </parent>
626+ <groupId>com.example</groupId>
627+ <artifactId>demo</artifactId>
628+ <version>0.0.1-SNAPSHOT</version>
629+ <dependencies>
630+ <dependency>
631+ <groupId>jakarta.annotation</groupId>
632+ <artifactId>jakarta.annotation-api</artifactId>
633+ <version>2.0.0</version>
634+ </dependency>
635+ <dependency>
636+ <groupId>org.springframework.boot</groupId>
637+ <artifactId>spring-boot-starter-web</artifactId>
638+ </dependency>
639+ </dependencies>
640+ </project>
641+ """
642+ ),
643+ srcMainJava (
644+ //language=java
645+ java (
646+ """
647+ import jakarta.annotation.Nonnull;
648+
649+ public class TestApplication {
650+ @Nonnull
651+ public String upperCase(@Nonnull String input) {
652+ return input.toUpperCase();
653+ }
654+ }
655+ """
656+ )
657+ )
658+ )
659+ );
660+ }
661+
662+ @ Test
663+ void projectWithSpringBoot3StarterWebShouldNotRemoveJakartaDependencyWhenUsingNullableAnnotation () {
664+ rewriteRun (
665+ spec -> spec .parser (JavaParser .fromJavaVersion ().dependsOn (javaxServlet , jakartaAnnotation )),
666+ mavenProject (
667+ "Sample" ,
668+ //language=xml
669+ pomXml (
670+ """
671+ <project>
672+ <modelVersion>4.0.0</modelVersion>
673+ <parent>
674+ <groupId>org.springframework.boot</groupId>
675+ <artifactId>spring-boot-starter-parent</artifactId>
676+ <version>3.2.5</version>
677+ <relativePath/> <!-- lookup parent from repository -->
678+ </parent>
679+ <groupId>com.example</groupId>
680+ <artifactId>demo</artifactId>
681+ <version>0.0.1-SNAPSHOT</version>
682+ <dependencies>
683+ <dependency>
684+ <groupId>jakarta.annotation</groupId>
685+ <artifactId>jakarta.annotation-api</artifactId>
686+ <version>1.3.5</version>
687+ </dependency>
688+ <dependency>
689+ <groupId>org.springframework.boot</groupId>
690+ <artifactId>spring-boot-starter-web</artifactId>
691+ </dependency>
692+ </dependencies>
693+ </project>
694+ """ ,
695+ """
696+ <project>
697+ <modelVersion>4.0.0</modelVersion>
698+ <parent>
699+ <groupId>org.springframework.boot</groupId>
700+ <artifactId>spring-boot-starter-parent</artifactId>
701+ <version>3.2.5</version>
702+ <relativePath/> <!-- lookup parent from repository -->
703+ </parent>
704+ <groupId>com.example</groupId>
705+ <artifactId>demo</artifactId>
706+ <version>0.0.1-SNAPSHOT</version>
707+ <dependencies>
708+ <dependency>
709+ <groupId>jakarta.annotation</groupId>
710+ <artifactId>jakarta.annotation-api</artifactId>
711+ <version>2.0.0</version>
712+ </dependency>
713+ <dependency>
714+ <groupId>org.springframework.boot</groupId>
715+ <artifactId>spring-boot-starter-web</artifactId>
716+ </dependency>
717+ </dependencies>
718+ </project>
719+ """
720+ ),
721+ srcMainJava (
722+ //language=java
723+ java (
724+ """
725+ import jakarta.annotation.Nullable;
726+
727+ public class TestApplication {
728+ @Nullable
729+ public String safeUpperCase(@Nullable String input) {
730+ return input == null ? null : input.toUpperCase();
731+ }
732+ }
733+ """
734+ )
735+ )
736+ )
737+ );
738+ }
739+
740+ @ Test
741+ void multiProjectWithSpringBoot3StarterWebShouldRemoveJakartaDependencyWhenUsingNullableAnnotationWhenApplicable () {
742+ rewriteRun (
743+ spec -> spec .beforeRecipe (withToolingApi ()).parser (JavaParser .fromJavaVersion ().dependsOn (javaxServlet , jakartaAnnotation )),
744+ mavenProject ("multi-project-build" ,
745+ //language=groovy
746+ settingsGradle ("""
747+ include 'project-with-null-annotations'
748+ include 'project-without-null-annotations'
749+ """ ),
750+ mavenProject ("project-with-null-annotations" ,
751+ //language=groovy
752+ buildGradle (
753+ """
754+ plugins {
755+ id 'java'
756+ }
757+
758+ repositories {
759+ mavenCentral()
760+ }
761+
762+ dependencies {
763+ implementation 'jakarta.annotation:jakarta.annotation-api:1.3.5'
764+ implementation 'org.springframework.boot:spring-boot-starter-web'
765+ }
766+ """ ,
767+ """
768+ plugins {
769+ id 'java'
770+ }
771+
772+ repositories {
773+ mavenCentral()
774+ }
775+
776+ dependencies {
777+ implementation 'jakarta.annotation:jakarta.annotation-api:2.0.0'
778+ implementation 'org.springframework.boot:spring-boot-starter-web'
779+ }
780+ """
781+ ),
782+ srcMainJava (
783+ //language=java
784+ java (
785+ """
786+ import jakarta.annotation.Nullable;
787+
788+ public class TestApplication {
789+ @Nullable
790+ public String safeUpperCase(@Nullable String input) {
791+ return input == null ? null : input.toUpperCase();
792+ }
793+ }
794+ """
795+ )
796+ )
797+ ),
798+ mavenProject ("project-without-null-annotations" ,
799+ //language=groovy
800+ buildGradle (
801+ """
802+ plugins {
803+ id 'java'
804+ }
805+
806+ repositories {
807+ mavenCentral()
808+ }
809+
810+ dependencies {
811+ implementation 'org.springframework.boot:spring-boot-starter-web'
812+ }
813+ """
814+ )
815+ )
816+ )
817+ );
818+ }
819+
577820 @ Test
578821 void upgradeAnnotationApiFromV1ToV2 () {
579822 rewriteRun (
0 commit comments