Skip to content

Commit f3227f7

Browse files
authored
Bump Kotlin 2.0-2.2 to 2.3 so Kotlin modules can reach Java 25 (#1139)
* Bump Kotlin 2.0-2.2 to 2.3 so Kotlin modules reach Java 25 * Floor Kotlin 2.0-2.2 modules at Java 24 as a bump safety net * Explain the Java 24 safety-net floor in UpgradeKotlinForJava25 * Rename UpgradeBuildToJava24 to UpgradeBuildToJava24ForKotlin1x * Comment both Kotlin 1.x caps and 2.x bump-fallbacks left at Java 24 Make CommentJava24KotlinCap self-healing (add at Java 24, remove once the module reaches a higher version) and run it last via a new CommentKotlinModulesCappedAtJava24 wrapper scoped to Kotlin modules, so the explanation lands on every Kotlin module that truly stays at Java 24 without leaving a stale comment on modules that reach Java 25.
1 parent a602847 commit f3227f7

4 files changed

Lines changed: 278 additions & 20 deletions

File tree

src/main/java/org/openrewrite/java/migrate/CommentJava24KotlinCap.java

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ public class CommentJava24KotlinCap extends Recipe {
4040

4141
private static final String KOTLIN_GROUP = "org.jetbrains.kotlin";
4242

43+
// Stable prefix shared by every emitted comment; used to recognise (and remove) a previously added comment even
44+
// after the named `kotlin-stdlib` version has changed.
45+
private static final String COMMENT_PREFIX = " Capped at Java 24:";
46+
4347
private static final Set<String> JAVA_VERSION_PROPERTIES = new HashSet<>(Arrays.asList(
4448
"maven.compiler.release",
4549
"maven.compiler.source",
@@ -51,8 +55,10 @@ public class CommentJava24KotlinCap extends Recipe {
5155
String description = "Adds an explanatory comment to Maven `pom.xml` files in modules that were held at Java 24 " +
5256
"because they compile Kotlin and depend on `kotlin-stdlib` older than 2.3, which cannot target Java 25 " +
5357
"bytecode. The comment names the `kotlin-stdlib` version found and the next step needed to reach Java 25. " +
54-
"Intended to run scoped behind the same preconditions as `UpgradeBuildToJava24`, right after the version " +
55-
"is capped.";
58+
"Self-healing: the comment is added while the module is at Java 24 and removed again once the module " +
59+
"reaches a higher Java version (for instance after its Kotlin was upgraded to 2.3), so it only ever remains " +
60+
"on modules that truly stay at Java 24 — whether a Kotlin 1.x cap or a 2.0-2.2 module whose Kotlin upgrade " +
61+
"could not be applied. Intended to run last, scoped to modules that compile Kotlin.";
5662

5763
@Override
5864
public TreeVisitor<?, ExecutionContext> getVisitor() {
@@ -63,10 +69,13 @@ public TreeVisitor<?, ExecutionContext> getVisitor() {
6369
@Override
6470
public Xml.Tag visitTag(Xml.Tag tag, ExecutionContext ctx) {
6571
Xml.Tag t = super.visitTag(tag, ctx);
66-
if ("properties".equals(t.getName()) && capsJavaAt24(t)) {
67-
String text = comment();
68-
if (!alreadyCommented(t, text)) {
69-
return addCommentAsFirstChild(t, text);
72+
if ("properties".equals(t.getName())) {
73+
if (capsJavaAt24(t)) {
74+
if (!hasCapComment(t)) {
75+
return addCommentAsFirstChild(t, comment());
76+
}
77+
} else if (hasCapComment(t)) {
78+
return removeCapComment(t);
7079
}
7180
}
7281
return t;
@@ -91,7 +100,7 @@ private boolean capsJavaAt24(Xml.Tag properties) {
91100

92101
private String comment() {
93102
if (commentText == null) {
94-
commentText = " Capped at Java 24: this module compiles Kotlin and depends on " + kotlinStdlibCoordinate() +
103+
commentText = COMMENT_PREFIX + " this module compiles Kotlin and depends on " + kotlinStdlibCoordinate() +
95104
", and Kotlin before 2.3 cannot target Java 25 bytecode. " +
96105
"Upgrade Kotlin (kotlin-stdlib and the Kotlin compiler) to 2.3 or later, " +
97106
"then re-run \"Migrate to Java 25\" to move this module to Java 25. ";
@@ -110,13 +119,13 @@ private String kotlinStdlibCoordinate() {
110119
return "kotlin-stdlib (older than 2.3)";
111120
}
112121

113-
private boolean alreadyCommented(Xml.Tag tag, String text) {
122+
private boolean hasCapComment(Xml.Tag tag) {
114123
List<? extends Content> content = tag.getContent();
115124
if (content == null) {
116125
return false;
117126
}
118127
for (Content c : content) {
119-
if (c instanceof Xml.Comment && text.equals(((Xml.Comment) c).getText())) {
128+
if (c instanceof Xml.Comment && ((Xml.Comment) c).getText().startsWith(COMMENT_PREFIX)) {
120129
return true;
121130
}
122131
}
@@ -129,6 +138,12 @@ private Xml.Tag addCommentAsFirstChild(Xml.Tag tag, String text) {
129138
Xml.Comment comment = new Xml.Comment(Tree.randomId(), prefix, Markers.EMPTY, text);
130139
return tag.withContent(ListUtils.concat(comment, content));
131140
}
141+
142+
@SuppressWarnings("unchecked")
143+
private Xml.Tag removeCapComment(Xml.Tag tag) {
144+
return tag.withContent(ListUtils.map((List<Content>) tag.getContent(), c ->
145+
c instanceof Xml.Comment && ((Xml.Comment) c).getText().startsWith(COMMENT_PREFIX) ? null : c));
146+
}
132147
};
133148
}
134149
}

src/main/resources/META-INF/rewrite/java-version-25.yml

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ preconditions:
2828
- org.openrewrite.Singleton
2929
recipeList:
3030
- org.openrewrite.java.migrate.UpgradeToJava21
31-
- org.openrewrite.java.migrate.UpgradeBuildToJava24
31+
- org.openrewrite.java.migrate.UpgradeKotlinForJava25
32+
- org.openrewrite.java.migrate.UpgradeBuildToJava24ForKotlin1x
3233
- org.openrewrite.java.migrate.UpgradeBuildToJava25
3334
- org.openrewrite.java.migrate.UpgradeBuildToJava25ForKotlin
3435
- org.openrewrite.java.migrate.UpgradePluginsForJava25
@@ -43,6 +44,9 @@ recipeList:
4344
- org.openrewrite.java.migrate.SystemGetSecurityManagerToNull
4445
- org.openrewrite.java.migrate.MigrateZipErrorToZipException
4546
- org.openrewrite.java.migrate.MigrateGraalVMResourceConfig
47+
# Run last, once every module has reached its final Java version: comment the Kotlin modules that truly stayed at
48+
# Java 24 (a Kotlin 1.x cap, or a 2.0-2.2 module whose Kotlin upgrade could not be applied).
49+
- org.openrewrite.java.migrate.CommentKotlinModulesCappedAtJava24
4650

4751
---
4852
type: specs.openrewrite.org/v1beta/recipe
@@ -229,20 +233,77 @@ recipeList:
229233

230234
---
231235
type: specs.openrewrite.org/v1beta/recipe
232-
name: org.openrewrite.java.migrate.UpgradeBuildToJava24
233-
displayName: Upgrade build to Java 24 for Kotlin pre-2.3
236+
name: org.openrewrite.java.migrate.UpgradeKotlinForJava25
237+
displayName: Upgrade Kotlin to 2.3 for Java 25 compatibility
234238
description: >-
235-
Kotlin versions before 2.3 only support up to Java 24. Applies only to modules that actually compile Kotlin
239+
Only Kotlin 2.3 and later can target Java 25 bytecode, so modules on an older Kotlin are otherwise capped at Java 24.
240+
This recipe upgrades modules that compile Kotlin (i.e. contain `.kt` source files) and are already on Kotlin 2.0, 2.1,
241+
or 2.2 up to the latest Kotlin 2.3, so they can subsequently be migrated to Java 25. Modules on Kotlin 1.x are left
242+
untouched, as crossing the K2 compiler default introduced in Kotlin 2.0 is a source-breaking change that should not be
243+
applied automatically. As a safety net the module is also floored at Java 24: if the Kotlin upgrade cannot be applied
244+
(for instance because the version is managed externally by a parent or BOM), the module still lands on Java 24 rather
245+
than being left behind, and is raised the rest of the way to Java 25 only once it actually reaches Kotlin 2.3.
246+
tags:
247+
- java25
248+
- kotlin
249+
preconditions:
250+
- org.openrewrite.java.migrate.search.ModuleHasKotlinSource
251+
- org.openrewrite.java.dependencies.search.ModuleHasDependency:
252+
groupIdPattern: org.jetbrains.kotlin
253+
artifactIdPattern: kotlin-stdlib*
254+
version: "[2.0,2.3)"
255+
recipeList:
256+
- org.openrewrite.java.dependencies.UpgradeDependencyVersion:
257+
groupId: org.jetbrains.kotlin
258+
artifactId: "*"
259+
newVersion: 2.3.x
260+
- org.openrewrite.maven.UpgradePluginVersion:
261+
groupId: org.jetbrains.kotlin
262+
artifactId: kotlin-maven-plugin
263+
newVersion: 2.3.x
264+
- org.openrewrite.gradle.plugins.UpgradePluginVersion:
265+
pluginIdPattern: org.jetbrains.kotlin.*
266+
newVersion: 2.3.x
267+
# Safety-net floor: if the Kotlin bump above could not be applied (e.g. the version is managed by a parent or BOM),
268+
# the module still lands on Java 24 rather than being left behind; it reaches Java 25 only once it is on Kotlin 2.3.
269+
- org.openrewrite.java.migrate.UpgradeJavaVersion:
270+
version: 24
271+
272+
---
273+
type: specs.openrewrite.org/v1beta/recipe
274+
name: org.openrewrite.java.migrate.UpgradeBuildToJava24ForKotlin1x
275+
displayName: Upgrade build to Java 24 for Kotlin 1.x
276+
description: >-
277+
Kotlin versions before 2.3 only support up to Java 24, and Kotlin 1.x cannot be safely upgraded automatically because
278+
crossing the K2 compiler default introduced in Kotlin 2.0 is a source-breaking change. Such modules are therefore
279+
capped at Java 24 and annotated with an explanation. Modules already on Kotlin 2.0-2.2 are instead bumped to Kotlin 2.3
280+
by `UpgradeKotlinForJava25` so they can reach Java 25. Applies only to modules that actually compile Kotlin
236281
(i.e. contain `.kt` source files), so transitive `kotlin-stdlib` dependencies do not trigger the cap.
237282
preconditions:
238283
- org.openrewrite.java.migrate.search.ModuleHasKotlinSource
239284
- org.openrewrite.java.dependencies.search.ModuleHasDependency:
240285
groupIdPattern: org.jetbrains.kotlin
241286
artifactIdPattern: kotlin-stdlib*
242-
version: "[0,2.3)"
287+
version: "[0,2.0)"
243288
recipeList:
244289
- org.openrewrite.java.migrate.UpgradeJavaVersion:
245290
version: 24
291+
292+
---
293+
type: specs.openrewrite.org/v1beta/recipe
294+
name: org.openrewrite.java.migrate.CommentKotlinModulesCappedAtJava24
295+
displayName: Comment Kotlin modules capped at Java 24
296+
description: >-
297+
Adds an explanatory comment to Kotlin modules that remain at Java 24 after the Java 25 migration, because Kotlin before
298+
2.3 cannot target Java 25 bytecode. This covers both a Kotlin 1.x cap (which cannot be upgraded automatically) and a
299+
Kotlin 2.0-2.2 module whose upgrade to 2.3 could not be applied. Scoped to modules that actually compile Kotlin
300+
(i.e. contain `.kt` source files); the comment is self-healing, so a module that does reach Java 25 has it removed.
301+
tags:
302+
- java25
303+
- kotlin
304+
preconditions:
305+
- org.openrewrite.java.migrate.search.ModuleHasKotlinSource
306+
recipeList:
246307
- org.openrewrite.java.migrate.CommentJava24KotlinCap
247308

248309
---

0 commit comments

Comments
 (0)