From 00fd2a6db8007d72660c23d46e7d582726b78b35 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Wed, 1 Jul 2026 14:49:32 +0200 Subject: [PATCH 1/2] Skip UseEnumSetOf empty conversion for static fields to avoid circular class-init (#1157) --- .../java/migrate/util/UseEnumSetOf.java | 13 +++++++ .../java/migrate/util/UseEnumSetOfTest.java | 39 +++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/src/main/java/org/openrewrite/java/migrate/util/UseEnumSetOf.java b/src/main/java/org/openrewrite/java/migrate/util/UseEnumSetOf.java index d2155cd4f3..3087b71b01 100644 --- a/src/main/java/org/openrewrite/java/migrate/util/UseEnumSetOf.java +++ b/src/main/java/org/openrewrite/java/migrate/util/UseEnumSetOf.java @@ -78,6 +78,14 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation methodInvocat } if (args.get(0) instanceof J.Empty) { + // Skip the empty `Set.of()` -> `EnumSet.noneOf(E.class)` conversion for static + // field initializers: `EnumSet.noneOf` reflectively reads the enum's constants + // during class initialization, which can re-enter a not-yet-initialized enum and + // throw a misleading `ClassCastException` when two enums have a circular static + // dependency (issue #1157). + if (isStaticField(parent)) { + return mi; + } JavaType firstTypeParameter = ((JavaType.Parameterized) type).getTypeParameters().get(0); JavaType.ShallowClass shallowClass = JavaType.ShallowClass.build(firstTypeParameter.toString()); return JavaTemplate.builder("EnumSet.noneOf(" + shallowClass.getClassName() + ".class)") @@ -120,6 +128,11 @@ private boolean isAssignmentSetOfEnum(@Nullable JavaType type) { return false; } + private boolean isStaticField(Cursor parent) { + return parent.getValue() instanceof J.VariableDeclarations && + ((J.VariableDeclarations) parent.getValue()).hasModifier(J.Modifier.Type.Static); + } + private boolean isArrayParameter(final List args) { if (args.size() != 1) { return false; diff --git a/src/test/java/org/openrewrite/java/migrate/util/UseEnumSetOfTest.java b/src/test/java/org/openrewrite/java/migrate/util/UseEnumSetOfTest.java index ba78e21246..0dd3f47357 100644 --- a/src/test/java/org/openrewrite/java/migrate/util/UseEnumSetOfTest.java +++ b/src/test/java/org/openrewrite/java/migrate/util/UseEnumSetOfTest.java @@ -182,6 +182,45 @@ public void method() { ); } + @Issue("https://github.com/openrewrite/rewrite-migrate-java/issues/1157") + @Test + void dontConvertEmptySetOfInStaticField() { + //language=java + rewriteRun( + java( + """ + package com.helloworld; + + import java.util.Set; + + public enum ConfigType { + ENUM, + BOOLEAN, + INTEGER; + + public static final Set SUBSCRIBE_TO_ALL = Set.of(); + } + """, + spec -> spec.markers(javaVersion(25))), + java( + """ + package com.helloworld; + + import static com.helloworld.ConfigType.BOOLEAN; + import static com.helloworld.ConfigType.ENUM; + import static com.helloworld.ConfigType.INTEGER; + + public enum ConfigProperty { + TRIAL_TYPE(ENUM), + IS_TRIAL_ENABLED(BOOLEAN), + MIN_ACCOUNT_AGE_MINUTES(INTEGER); + + ConfigProperty(final ConfigType type) {} + } + """, + spec -> spec.markers(javaVersion(25)))); + } + @Issue("https://github.com/openrewrite/rewrite-migrate-java/issues/958") @Test void retainEmptySetOf() { From cb0397d4269e62b6adb63fddceb05fc09bd95ce3 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Wed, 1 Jul 2026 14:54:44 +0200 Subject: [PATCH 2/2] Prevent conversion of empty Set.of() in static fields Skip conversion for empty Set.of() in static field initializers to avoid ClassCastException. --- .../java/org/openrewrite/java/migrate/util/UseEnumSetOf.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/org/openrewrite/java/migrate/util/UseEnumSetOf.java b/src/main/java/org/openrewrite/java/migrate/util/UseEnumSetOf.java index 3087b71b01..07bf1a8b70 100644 --- a/src/main/java/org/openrewrite/java/migrate/util/UseEnumSetOf.java +++ b/src/main/java/org/openrewrite/java/migrate/util/UseEnumSetOf.java @@ -78,11 +78,6 @@ public J.MethodInvocation visitMethodInvocation(J.MethodInvocation methodInvocat } if (args.get(0) instanceof J.Empty) { - // Skip the empty `Set.of()` -> `EnumSet.noneOf(E.class)` conversion for static - // field initializers: `EnumSet.noneOf` reflectively reads the enum's constants - // during class initialization, which can re-enter a not-yet-initialized enum and - // throw a misleading `ClassCastException` when two enums have a circular static - // dependency (issue #1157). if (isStaticField(parent)) { return mi; }