diff --git a/src/main/resources/META-INF/rewrite/java-version-25.yml b/src/main/resources/META-INF/rewrite/java-version-25.yml
index 3d4fe18287..587ad1f8f5 100644
--- a/src/main/resources/META-INF/rewrite/java-version-25.yml
+++ b/src/main/resources/META-INF/rewrite/java-version-25.yml
@@ -220,6 +220,33 @@ recipeList:
groupId: net.bytebuddy
artifactId: byte-buddy*
newVersion: 1.17.x
+ # Both distributions bundle an AspectJ too old to read Java 25 bytecode, so aspectjtools is pinned on the plugin.
+ # dev.aspectj is otherwise interchangeable, but org.codehaus.mojo's `complianceLevel` default of 1.4 is now fatal.
+ - org.openrewrite.maven.ChangePluginGroupIdAndArtifactId:
+ oldGroupId: org.codehaus.mojo
+ oldArtifactId: aspectj-maven-plugin
+ newGroupId: dev.aspectj
+ newVersion: 1.14.x
+ - org.openrewrite.maven.AddPluginDependency:
+ pluginGroupId: dev.aspectj
+ pluginArtifactId: aspectj-maven-plugin
+ groupId: org.aspectj
+ artifactId: aspectjtools
+ version: 1.9.25.1
+ - org.openrewrite.xml.ChangeTagValue:
+ elementName: //plugin[artifactId='aspectj-maven-plugin']/configuration/complianceLevel
+ newValue: "25"
+ - org.openrewrite.java.dependencies.UpgradeDependencyVersion:
+ groupId: org.aspectj
+ artifactId: aspectj*
+ newVersion: 1.9.x
+ # mockito-inline was last published as 5.2.0 and inline mocking is the default in mockito-core 5.x, so fold it in
+ # before the bump below rather than leaving a coordinate that no longer resolves.
+ - org.openrewrite.java.dependencies.ChangeDependency:
+ oldGroupId: org.mockito
+ oldArtifactId: mockito-inline
+ newArtifactId: mockito-core
+ - org.openrewrite.maven.RemoveDuplicateDependencies
- org.openrewrite.java.dependencies.UpgradeDependencyVersion:
groupId: org.mockito
artifactId: mockito-*
diff --git a/src/test/java/org/openrewrite/java/migrate/UpgradeToJava25Test.java b/src/test/java/org/openrewrite/java/migrate/UpgradeToJava25Test.java
index 478f008121..c48df08575 100644
--- a/src/test/java/org/openrewrite/java/migrate/UpgradeToJava25Test.java
+++ b/src/test/java/org/openrewrite/java/migrate/UpgradeToJava25Test.java
@@ -508,4 +508,139 @@ void addsLombokAnnotationProcessor() {
)
);
}
+
+ @Test
+ void mockitoInlineFoldedIntoMockitoCore() {
+ // mockito-inline was last published as 5.2.0, so bumping a shared mockito version property would otherwise
+ // leave it unresolvable; inline mocking is the default in mockito-core 5.x.
+ rewriteRun(
+ mavenProject("project",
+ pomXml(
+ //language=xml
+ """
+
+ com.mycompany.app
+ my-app
+ 1
+
+ 17
+ 5.2.0
+
+
+
+ org.mockito
+ mockito-inline
+ ${mockito.version}
+ test
+
+
+
+ """,
+ spec -> spec.after(actual ->
+ assertThat(actual)
+ .contains("25")
+ .doesNotContain("mockito-inline")
+ .contains("mockito-core")
+ .containsPattern("5\\.17\\.")
+ .actual())
+ )
+ )
+ );
+ }
+
+ @Test
+ void mockitoInlineAlongsideMockitoCoreLeavesNoDuplicate() {
+ rewriteRun(
+ mavenProject("project",
+ pomXml(
+ //language=xml
+ """
+
+ com.mycompany.app
+ my-app
+ 1
+
+ 17
+ 5.2.0
+
+
+
+ org.mockito
+ mockito-core
+ ${mockito.version}
+ test
+
+
+ org.mockito
+ mockito-inline
+ ${mockito.version}
+ test
+
+
+
+ """,
+ spec -> spec.after(actual ->
+ assertThat(actual)
+ .doesNotContain("mockito-inline")
+ .containsOnlyOnce("mockito-core")
+ .containsPattern("5\\.17\\.")
+ .actual())
+ )
+ )
+ );
+ }
+
+ @Test
+ void upgradesAspectJMavenPluginForJava25() {
+ // Only AspectJ 1.9.25 and later can read Java 25 bytecode, and neither plugin distribution bundles a compiler
+ // that new, so aspectjtools is pinned on the plugin itself.
+ rewriteRun(
+ mavenProject("project",
+ pomXml(
+ //language=xml
+ """
+
+ com.mycompany.app
+ my-app
+ 1
+
+ 8
+ 8
+
+
+
+ org.aspectj
+ aspectjrt
+ 1.8.13
+
+
+
+
+
+ org.codehaus.mojo
+ aspectj-maven-plugin
+ 1.11
+
+ ${maven.compiler.source}
+ ${maven.compiler.target}
+ 1.8
+
+
+
+
+
+ """,
+ spec -> spec.after(actual ->
+ assertThat(actual)
+ .contains("25")
+ .doesNotContain("org.codehaus.mojo")
+ .containsPattern("dev.aspectj\\s*aspectj-maven-plugin\\s*1\\.14\\.")
+ .containsPattern("aspectjtools\\s*1\\.9\\.25")
+ .contains("25")
+ .containsPattern("aspectjrt\\s*1\\.9\\.")
+ .actual())
+ )
+ )
+ );
+ }
}