Repository navigation
Description
We triaged all recipes in this repo against our recipe review checklist (the one used for openrewrite/rewrite-spring#1201). That covers 205 Java recipe classes and 292 declarative recipes in 52 YAML files. This issue tracks what we found, grouped so each item can be picked up independently.
Each item is self-contained, so you can pick one up on its own or point an agent at it ("work on item F1 of this issue"). Please reference the item ID in your PR title or description. As soon as the PR is opened, tick the item's box and add the PR number after its title, e.g. (#1234), so nobody else picks it up. If the PR only covers some bullets, also add "Fixed in #1234." to those bullets. Untick the box if the PR is closed without merging. Where an item overlaps an existing issue, that issue is linked.
How to pick up an item
- Line numbers are against
mainatac6f4827and may have drifted, so search by symbol if needed. - Paths are abbreviated:
M/=src/main/java/org/openrewrite/java/migrate/T/=src/test/java/org/openrewrite/java/migrate/Y/=src/main/resources/META-INF/rewrite/
- Confirmed means someone traced the code path and the behaviour is certain; no probe test has been run yet. Suspected means it was inferred from reading. Write the probe test first; if it does not reproduce, close the item with a note.
- Prefer bailing out (making no change) over guessing when a recipe can't preserve semantics.
- Every fix comes with a test. Tests use realistic classpaths and avoid
TypeValidation.none(). Expected output must be correct, not just a record of today's behaviour. - Use one concern per commit, with an imperative headline that names APIs in backticks.
- Items in A need a maintainer decision first. Comment on the issue before starting.
- When you open a PR, tick the item and link the PR right away (see above).
Start here: the most harmful confirmed items
These change behaviour silently or break the build, and are reached through the main upgrade composites:
- G1:
HttpSessionInvalidatereplacessession.invalidate()withrequest.logout()in everyJavaxMigrationToJakartarun. - B1:
AddLombokMapstructBindingcreatesannotationProcessorPathswithout Lombok inUpgradeToJava17. - F1:
UseLombokSetterdeletes setters that transform their argument. - E1 and D1:
Set.of/Map.ofthrow on duplicates and nulls where the replaced code didn't. - C1–C3: the Java 21 switch restyles drop branches or change control flow.
- B3: Docker tags become ones that don't exist.
- G7: Faces 3 text replacements stop the Faces 4 XML updates from running.
- C5:
ThreadStopUnsupportedleaves unreachable code.
A. Wiring & placement (decide first)
-
A1 Move opinionated restyles out of the mandatory version upgrades
Details
- Problem: these change style or semantics in code that compiles fine on the new JDK. Each also has its own bugs (see C/D).
UpgradeToJava21(Y/java-version-21.yml:44-47):NullCheckAsSwitchCase,IfElseIfConstructToSwitch,SwitchCaseAssignmentsToSwitchExpression,SwitchCaseReturnsToSwitchExpression.UpgradeToJava25:ReplaceSystemOutWithIOPrint(Y/java-version-25.yml:36).MigrateMainMethodToInstanceMainwas deliberately kept inJavaBestPracticesonly (Y/java-best-practices.yml:34-36).Java8toJava11→UpdateLombokToJava11(Y/lombok.yml:79-83): rewritesvaltofinal var, and writeslombok.val.flagUsage = errorinto everylombok.config, althoughvalstill works on Lombok 1.18.
- Fix: move them to
JavaBestPractices(or aJava21BestPractices), and keep only what the JDK upgrade requires.
- Problem: these change style or semantics in code that compiles fine on the new JDK. Each also has its own bugs (see C/D).
-
A2 Vendor switches and scope changes reached by every Jakarta EE / Java 11+ migration
Details
-
Provider switches:
JavaxMigrationToJakarta(Y/jakarta-ee-9.yml:32) includesjavaee8→javaee7→javaee6, and those switch providers:- OpenJPA → EclipseLink in
persistence.xml(Y/java-ee-7.yml:29,35). - Apache BVal → Hibernate Validator in
validation.xml(Y/java-ee-8.yml:31,61).ApacheDefaultProvider's display name says "Flags", but it rewrites.
That is right on WebSphere Liberty and wrong on TomEE. The same chain brings
JpaCacheProperties(G5) andHttpSessionInvalidate(G1). - OpenJPA → EclipseLink in
-
IBMSemeru(Y/ibm-java.yml:33-34→:133-180): includesRemovedJavaXMLWSModuleProvidedandRemovedJaxBModuleProvided, whose own display names say "in WebSphere Liberty applications". They set the JAXB/JAX-WS API toprovided, so a non-Liberty app loses JAXB at runtime. SUSPECTED. -
AddCommonAnnotationsDependencies(Y/add-common-annotations-dependencies.yml:42-45): setsjakarta.annotation-apitoprovidedunconditionally in every Java 11+ upgrade (Maven only). A shaded Java SE app loses the API at runtime. SUSPECTED. -
Fix: move the vendor and Liberty specifics into the IBM/OpenJPA composites, or gate them on the provider or on
war/earpackaging.
-
-
A3
JavaBestPractices→JavaUtilAPIsre-enables recipes the Java 11 chain disabledDetails
- Where:
Y/java-best-practices.yml:64. - Problem:
JavaUtilAPIsbrings back the null-unsafe collection factories that were left out of the Java 11 chain for null safety (Collections.singleton and Collections.singletonList allow null, Set.of and List.of not #250); see D1/D2. It also bringsUseEnumSetOf("too opinionated", UseEnumSetOf is too opinionated for Spring Boot / Java upgrades #958) withconvertEmptySetat its defaulttrue, and re-runs 10 Java recipes already in theUpgradeToJava25chain (Java recipes are not Singleton-guarded). - Conflict:
RemoveFinalizerFromZip(Y/java-util-apis.yml:39) deletes the zipfinalize()calls, whileRemovedZipFinalizeMethods(Y/java-version-17.yml:206-228) renames them toend()/close(). Pick one. - Fix: list only the
JavaUtilAPIsentries that aren't already in the chain, and decide on the null-unsafe ones.
- Where:
-
A4 Wire, document as opt-in, or delete unreachable recipes
Details
24 of 205 Java recipes are referenced by no composite.
- Wire:
io.AddInputStreamBulkReadMethod,lang.StringRulesRecipesandlang.UseStringIsEmptyRecipe→JavaBestPractices.search.FindLocaleDateTimeFormats→UpgradeToJava21, as Java 25 does withFindCompletableFutureDefaultExecutor.lombok.AdoptLombokGetterMethodNames/AdoptLombokSetterMethodNames→LombokBestPractices, but only after F3.
- Document as opt-in:
AddSurefireFailsafeArgLine(after B6),LombokValueToRecord,AddStopBubblingToLombokConfig,ConsolidateLombokConfig,search.*(FindJavaVersion,PlanJavaMigration,AboutJavaVersion,FindInternalJavaxApis,FindDtoOverfetching,FindDataUsedOnDto),lang.FindThreadStartInConstructor,UseTabsOrSpaces(arguably rewrite-static-analysis). - Delete or rewrite (each is broken; see the referenced items):
RemovedSubjectMethods(D9),DontOverfetchDto(H2),AddScopeToInjectedClass(G9),JacksonProviderOverrides(G9),metrics.SimplifyMicrometerMeterTags(D10, or move it to rewrite-micrometer). Also:AddJDeprScanPlugin:@Incubating, pins3.0.0-alpha-1, untested, and adds the plugin to every pom despite its javadoc.AddSuppressionForIllegalReflectionWarningsPlugin: configuresmaven-jar-pluginonwar/ear, where it doesn't run. It is a no-op with no test.
- Duplicate:
io.ReplaceFileInOrOutputStreamFinalizeWithCloseduplicates YAMLRemovedFileIOFinalizeMethods(Y/java-version-17.yml:290-307). Delete one. - Unreferenced YAML building blocks:
ComIntelliJAnnotationsToOrgJetbrainsAnnotations(add toMigrateToJSpecifybeforeMigrateFromJetbrainsAnnotations),WasDevMvnChangeParentArtifactId,AddJaxbDependenciesWithoutRuntime.
- Wire:
-
A5 Remove duplicate and dead entries (Stop running the same recipe twice in the Java 8, 11, 21 and Faces 4.1 migrations #1340, Stop half-migrating
javax.servletinRemovalsServletJakarta10and add Jakarta APIs for subpackage-only users #1343)Details
Y/java-version-21.yml:50:RemoveIllegalSemicolonsis a deprecated wrapper ofRemoveExtraSemicolons, which:32already runs. Fixed in Stop running the same recipe twice in the Java 8, 11, 21 and Faces 4.1 migrations #1340.Y/jakarta-faces-41.yml:29:Faces2xMigrationToJakartaFaces3xis already reached via:30, so it is reached four times insideJakartaEE11. Fixed in Stop running the same recipe twice in the Java 8, 11, 21 and Faces 4.1 migrations #1340.Y/java-version-8.yml:34-35:Thread.destroy()removal duplicatesThreadStopDestroy(Y/java-version-11.yml:233-234) and sits before the JDK 11 removal. Fixed in Stop running the same recipe twice in the Java 8, 11, 21 and Faces 4.1 migrations #1340.Y/java-version-11.yml:125-128:jaxb2-maven-plugin2.5.x is bumped again byAddJaxbAPIDependencies(Y/jaxb-apis.yml:139-142). Fixed in Stop running the same recipe twice in the Java 8, 11, 21 and Faces 4.1 migrations #1340.Y/jakarta-ee-10.yml:332+: the sevenChangeType javax.servlet.*entries inRemovalsServletJakarta10are dead inside the composite, and half-migrate when run standalone. Fixed in Stop half-migratingjavax.servletinRemovalsServletJakarta10and add Jakarta APIs for subpackage-only users #1343.
-
A6 Placement questions
Details
UpgradeToJava6bumps JaCoCo (Y/java-version-6.yml:29). Move it toUpgradePluginsForJava11+.UpgradeToJava21callsSetupJavaUpgradeJavaVersionwith no option (Y/java-version-21.yml:40), so it relies on the upstream default being 21. Move it toUpgradePluginsForJava21withminimumJavaMajorVersion: 21.MigrateFastjsonForJakarta10(Y/jakarta-ee-10.yml:56,812) is a fastjson1 → 2 library migration insideJakartaEE10(see also G8).UpgradeJavaForJetty12(Y/jakarta-ee-9.yml:1679-1686) bumps the build to Java 17 inside an EE 9 migration, without theUpgradeToJava17source fixes.JakartaEE11(Y/jakarta-ee-11.yml:19-58) leaves servlet, persistence, cdi, validation, el, ws.rs and websocket on EE 10 versions, and doesn't ensure Java 17. Its description says it "flags", but it doesn't.- Library bumps in Java composites have no stated JDK reason:
Y/java-version-17.yml:55-81(guice, commons-codec, spotbugs, mapstruct) andY/java-version-21.yml:82-94(guava29.0, byte-buddy, modelmapper). EnableLombokAnnotationProcessoris defined inY/java-version-25.yml:172but first used inUpgradeToJava17. Move it tojava-version-17.ymlorlombok.yml.UpdateAnnotationAttributeJavaxToJakarta(Y/jakarta-ee-10.yml:39-44) fixes"javax.jms.Queue"string attributes that go stale at EE 9. Move it toJavaxMigrationToJakarta.- The Kotlin floor
UpgradeJavaVersion(24)(Y/java-version-25.yml:315-334) also moves Dockerfiles, CI images and.sdkmanrcto the EOL non-LTS 24. Give the floor a build-only variant. SUSPECTED.
B. Build files, dependencies & multi-module
-
B1
AddLombokMapstructBindingcreatesannotationProcessorPathswithout Lombok (Keep Lombok running whenAddLombokMapstructBindingcreatesannotationProcessorPaths#1335)Details
- Where:
M/AddMapstructAnnotationProcessorPath.java:74-80, reached fromY/java-version-17.yml:355-381. - Problem (CONFIRMED): when Lombok is a plain dependency and there is no
<annotationProcessorPaths>, the recipe creates one holding onlylombok-mapstruct-bindingandmapstruct-processor. Once paths are explicit, javac stops discovering processors on the classpath, so Lombok no longer runs and every@Getter/@Buildercaller fails afterUpgradeToJava17.T/AddLombokMapstructBindingTest.java:203-275expects this output. - Fix: when creating the list, also add
org.projectlombok:lombokat its resolved version. Otherwise only add to an existing list. - Also (SUSPECTED,
:63-68):mapstructVersionis global, so the first module scanned wins. Key it per project. See alsoAddLombokMapstructBindingadds redundant dependency whenlombok-mapstruct-bindingis already configured inmaven-compiler-pluginannotationProcessorPaths#1319 and Lombok annotation processor not added to modules of a Maven multi-module project #1119.
- Where:
-
B2
UpgradeKotlinJvmTargetVersion: targets beyond the Kotlin compiler, and missed shapesDetails
- Where:
M/UpgradeKotlinJvmTargetVersion.java:106-110,139-148,248-276, reached through the Kotlin-cappedUpgradeJavaVersion(24)inY/java-version-25.yml:315-334. - Too-high target (CONFIRMED path): Kotlin 1.9 supports at most
jvmTarget21, and 2.0/2.1 are also below 24. Mavenkotlincfails with "Unknown JVM target version", and Gradle KTS can't resolveJvmTarget.JVM_24. Fix: cap at the resolved Kotlin version's maximum (1.9→21, 2.0→22, 2.1→23, 2.2→24). - Missed shapes (SUSPECTED):
kotlinOptions.jvmTarget = '11',compilerOptions.jvmTarget.set(..), GroovycompilerOptions { },JvmTarget.fromTarget("11"),<kotlin.compiler.jvmTarget>, and<jvmTarget>under<executions>. When the Java target moves but Kotlin's doesn't, KGP fails with "Inconsistent JVM-target compatibility". - Also: the Groovy/Kotlin visitors run over every
.groovy/.ktsource, not just build scripts (:72-89).
- Where:
-
B3
UpgradeDockerImageVersionproduces tags that don't exist (Drop pinned patch versions when upgrading Docker image tags (B3 of #1330) #1352)Details
- Where:
M/UpgradeDockerImageVersion.java:56,207-217. - Problem (CONFIRMED):
VERSIONED_TAG(\d{1,3})(\D.*)?keeps the patch as a suffix.eclipse-temurin:17.0.9_9-jdk→25.0.9_9-jdk,openjdk:8u342-jre→eclipse-temurin:25u342-jre,amazoncorretto:17.0.9→25.0.9. - Fix: drop the patch/update part, or skip pinned patch versions.
- Also (SUSPECTED,
:186-193): the switch fromopenjdktoeclipse-temurinkeeps OpenJDK-only variants (-slim,-slim-bullseye,-oraclelinux8,-buster), which Temurin doesn't publish.
- Where:
-
B4
AddJaxbRuntime: swaps runtimes in projects that don't use JAXB, possibly downgrading Jakarta JAXB 4Details
- Where:
M/javax/AddJaxbRuntime.java:186-206,233-247, reached viaY/jaxb-apis.yml:37fromJava8toJava11, and so from every Java 17/21/25 upgrade. - Problem (CONFIRMED for the unconditional swap): the
ChangeDependencydelegates run on every build file, even whenusesJaxbis false, socom.sun.xml.bind:jaxb-implbecomesorg.glassfish.jaxb:jaxb-runtime:2.3.x. SUSPECTED:ChangeDependencyGroupIdAndArtifactIdhas no downgrade guard, so a Jakartajaxb-impl:4.0.xends up on the javax 2.3 runtime. - Also:
usesJaxbis one repo-wide flag (:77,113); key it by project.- The description (
:66-70) namescompileOnly/provided, but the code addsruntimeOnly/runtime.
- Probe: a pom with
com.sun.xml.bind:jaxb-impl:4.0.5andjakarta.xml.bind-api:4.0.2, run throughJava8toJava11. - Related:
AddJaxbAPIDependenciessilently no-ops whenjavax.xml.bindis only JDK-provided #1246 and AddJaxwsRuntime blindly injects com.sun.xml.ws:jaxws-rt into projects using Apache CXF #1314.
- Where:
-
B5 Repo-wide flags in scanning recipes
Details
M/jakarta/HasJettyDependency.java:46-67,87(SUSPECTED): one globalAtomicBoolean. One module with an embedded Jetty 9 test server moves all modules to Java 17 and everyorg.eclipse.jetty:*to 12.0.x (Y/jakarta-ee-9.yml:1667-1685).M/search/ModuleHasKotlinSource.java:72-93withY/java-version-25.yml:359-366(SUSPECTED): a parent pom has no.ktfiles, soinvertMarkinglets it move to release 25, and Kotlin 1.x children inherit that. Probe: a parent withmaven.compiler.release=17and a Kotlin 1.9 child.M/jakarta/HasNoJakartaAnnotations.java:51-65withY/jakarta-ee-9.yml:1552-1564(SUSPECTED): it scans before the javax → jakarta rename, so ajavax.annotation.PostConstructuser counts as having "no Jakarta annotations", andjakarta.annotation-apiis removed on Boot 2.x.- See also B1 (
mapstructVersion) and B4 (usesJaxb).
-
B6
AddSurefireFailsafeArgLineadds@{argLine}without definingargLineDetails
- Where:
M/AddSurefireFailsafeArgLine.java:102-104,139-150(unreachable; see A4). - Problem (CONFIRMED): without JaCoCo, Surefire passes the literal
@{argLine}, and the forked JVM fails with "Could not find or load main class @{argLine}". The javadoc at:120-121claims otherwise. - Fix: reuse
AddMockitoJavaAgentToMavenSurefirePlugin:92-100,137-139, which handles exactly this case.
- Where:
-
B7 Lombok dependency handling
Details
EnableLombokAnnotationProcessor(Y/java-version-25.yml:187-192, SUSPECTED): the Gradleversion: "[1.18.40)"has no comma and is probably written verbatim, so Gradle can't resolve it; only Maven is tested. AlsoonlyIfUsing: lombok.*misseslombok.extern..*andlombok.experimental..*.LombokBestPractices(Y/lombok.yml:42-44, SUSPECTED):ExcludeDependency org.projectlombok:lombokalso excludes it from modules without a direct Lombok dependency, which is exactly the shape ofT/lombok/LombokBestPracticesTest.java:131-222. Modules that use Lombok then fail to compile.- Maven-only: the scope change and exclusion (
Y/lombok.yml:34-44) skip Gradle. - Multi-module:
EnableLombokAnnotationProcessorchanges no pom when only one child of an aggregator uses Lombok. The root cause is AddAnnotationProcessor: child with in-reactor parent is silently skipped when only the child passes the precondition rewrite#7850. See Lombok annotation processor not added to modules of a Maven multi-module project #1119.
-
B8
onlyIfUsingglobs (Addjspecifydependency when migrating Micrometerio.micrometer.core.langannotations #1338, Stop half-migratingjavax.servletinRemovalsServletJakarta10and add Jakarta APIs for subpackage-only users #1343)Details
Y/jspecify.yml:170(CONFIRMED):MigrateFromMicrometerAnnotationshasonlyIfUsing: org.springframework.lang.*ull*, copied from the Spring recipe. Micrometer users don't get jspecify; Spring users get an unused dependency. It should beio.micrometer.core.lang.*ull*. Fixed in Addjspecifydependency when migrating Micrometerio.micrometer.core.langannotations #1338.Y/jakarta-ee-9.yml(SUSPECTED):javax.servlet.*(:862),javax.ws.rs.core.*(:1908) andjavax.mail.*(:1867) miss subpackages. The other 27 entries use..*. Fixed in Stop half-migratingjavax.servletinRemovalsServletJakarta10and add Jakarta APIs for subpackage-only users #1343.
-
B9 Maven-only recipes in shared composites
Details
-
AddMockitoJavaAgentToMavenSurefirePlugin(Y/java-version-25.yml:258): Gradle projects using Mockito get nothing under Java 25. -
CommentJava24KotlinCap(M/CommentJava24KotlinCap.java:68): Gradle Kotlin modules capped at 24 get no explanation. -
AddJakartaXmlBindRuntime,AddApiDependencyForImportsandRetainJaxbApiForArquillianRecorder(Y/jakarta-ee-9.yml:1019-1051): Gradle projects never get a Jakarta JAXB runtime. -
M/jakarta/DoesNotHaveProvidedApiDependency.java:53-70(SUSPECTED):- Maven: misses
providedinherited from the parent'sdependencyManagement. - Gradle: checks only
compileOnly, notprovidedCompile.
Either way, a compile-scope API gets added to WARs.
- Maven: misses
-
M/javax/AddJaxwsRuntime.java:103-108: the Gradle runtime goes intocompileOnly+testImplementation, so standalone apps lack it at runtime (documented). See also AddJaxwsRuntime blindly injects com.sun.xml.ws:jaxws-rt into projects using Apache CXF #1314, and Investigate how to migrate CXF projects to Java 11 #28 for CXF projects, where a JAX-WS runtime shouldn't be added at all.
-
-
B10
MigrateGraalVMResourceConfigloses resourcesDetails
- Where:
M/MigrateGraalVMResourceConfig.java, inUpgradeToJava25(Y/java-version-25.yml:45). - Quoted patterns (CONFIRMED,
:320-381):\Q...\E, whichnative-image-agentemits for every literal resource, becomes a glob that matches nothing. - Excludes (CONFIRMED,
:115,139-157):excludesare always dropped. When some includes can't be converted, the file ends up half old format and half new. - Target format (SUSPECTED): writing
"resources": [ {"glob": ..} ]intoresource-config.jsonmay not be what GraalVM's legacy parser accepts there. CheckLegacyResourceConfigurationParserbefore fixing the rest.
- Where:
-
B11 Smaller build-file items
Details
M/UpgradeUnmodeledMavenJavaVersion.java:46-52(SUSPECTED): bumps fixture poms undersrc/test/resources,src/itandarchetype-resources.M/UpdateSdkMan.java:92-94,134(SUSPECTED): only the root.sdkmanrcis handled, and a commented#java=line can match.M/UpgradeJavaCiContainerImage.java:37: the display name says CircleCI only, but it also covers GitHub Actions.
C. Java language migrations (lang, lang/var)
-
C1
IfElseIfConstructToSwitch: wrongcase null,breakretargeted, dominated labels (Leave if-else-if chains alone when a switch would change behaviour or not compile #1336)Details
- Where:
M/lang/IfElseIfConstructToSwitch.java, inUpgradeToJava21. - Null check on another variable (CONFIRMED,
:127-144,201-213): a leading null check on a different variable still becomescase nullof the switch.nullCaseInSwitchonly feeds the case count. A second null check overwrites the first, and the first branch's body is lost. Probe:if (other == null) a(); else if (o instanceof Integer i) b(); else if (o instanceof Long l) c(); else d();. - Retargeted
break(CONFIRMED,:171-175): onlyreturnis rejected. An unlabeledbreaknow exits the new switch instead of the enclosing loop. - Dominance (CONFIRMED):
instanceof CharSequencebeforeinstanceof Stringproduces a dominated label, which is a compile error. - Related: IfElseIfConstructToSwitch drops leading comments inside single-statement blocks and creates 2-case switches (SonarQube S1301) #1305 (comments dropped) and Enhance IfElseIfConstructToSwitch to support "return" statements #776.
- Where:
-
C2
NullCheckAsSwitchCasedrops theelsebranch (Do not drop theelsebranch when merging a null check into a switch #1331)Details
- Where:
M/lang/NullCheckAsSwitchCase.java:69-98andM/lang/NullCheck.java:43-46, inUpgradeToJava21. - Problem (CONFIRMED):
if (s == null) { a(); } else { b(); } switch (s) {..}removes theifand keeps onlya()ascase null, sob()is gone. Fix: requirewhenNotNull() == null. - Design question: the recipe only fires when the null branch falls through into the switch, which today throws an NPE. The rewrite turns that NPE into normal completion, while the truly equivalent shape (a null branch ending in
return/throw) is rejected. Consider inverting the rule.
- Where:
-
C3
SwitchCaseAssignmentsToSwitchExpression: labeledbreak, selector readsDetails
- Where:
M/lang/SwitchCaseAssignmentsToSwitchExpression.java, inUpgradeToJava21. - Labeled break (CONFIRMED,
:176):x = 5; break outer;becomesyield 5, so the loop is no longer left. RequiregetLabel() == null. - Selector reads the variable (CONFIRMED,
:71-87,93-170):String s = "a"; switch (s) { case "a": s = "b"; ..}becomesString s = switch (s) {..}, which fails with "might not have been initialized". Withint x = i; switch (i++), the default branch reads the incrementedi. - Comments (SUSPECTED,
:111-119): comments in arrow blocks and in thebreakprefix are lost.
- Where:
-
C4 Other switch recipes
Details
SwitchCaseEnumGuardToLabel(CONFIRMED,:109-114): any identifier becomes a label, socase Suit s when s == fav ->becomescase fav ->. Require an enum-constant field type.RefineSwitchCases(CONFIRMED,:135-150): a non-block then/else part (return;,break;, a nestedif) becomes an arrow body, which is illegal. SUSPECTED (:72-75): a reassigned pattern variable can't be used in a guard.SwitchCaseReturnsToSwitchExpression(SUSPECTED,:58-61, test:336-372):- For an exhaustive enum switch without
default, the following fallbackreturn/throwis deleted, so new constants now throwMatchException. return;cases yield an invalidreturn switch.
- For an exhaustive enum switch without
-
C5
ThreadStopUnsupportedreplaces the call with athrowanywhereDetails
- Where:
M/lang/ThreadStopUnsupported.java:52-55. - Problem (CONFIRMED): on Java 21+,
t.stop()becomesthrow new UnsupportedOperationException()wherever it appears. Any following statement becomes unreachable (a compile error), and() -> t.stop()becomes() -> throw .., a syntax error. The tests only use the call as the last statement. - Fix: only replace a block's last statement, and otherwise just add the comment.
- Also:
- There's no
UsesMethodprecondition, andUsesJavaVersionruns again for every match. - The comment is a hand-built
TextComment; use theCommentstrait (K5).
- There's no
- Where:
-
C6
MigrateMainMethodToInstanceMainon interfaces, abstract classes, enums and recordsDetails
- Where:
M/lang/MigrateMainMethodToInstanceMain.java:90-151. - Problem (CONFIRMED): the class kind and
abstractaren't checked.interface Main { static void main(String[] a) {} }becomesvoid main() {}, which doesn't compile.- Abstract classes, enums and records with components get an instance main the launcher can't instantiate.
- Also (SUSPECTED,
:114,129-132): the Spring Boot guard misses meta-annotations and launchers that callSpringApplication.run(App.class, args).
- Where:
-
C7
UseVar*recipesDetails
UseVarForTypeCast(CONFIRMED,:50-59,84-89): bypassesDeclarationCheck.isVarApplicable. Fields of anonymous classes getvar, and so doesString s[] = (String[]) o; neither compiles. Fold it intoDeclarationCheck.UseVarForObject(CONFIRMED,:59-73):Object o = "a"; o = 1;narrows the type and breaks the reassignment. Mirror theisReassignedguard fromUseVarForGenericsConstructors:85.- SUSPECTED (
DeclarationCheck.java:444-466):- Kotlin isn't excluded.
- TYPE_USE annotations (for example JSpecify
@Nullable) stay in front ofvar, which javac rejects. - A
J.AnnotatedTypeloses its annotation.
- Related: UseVarForGenericMethodInvocations 'mvn rewrite:run' crash #698.
-
C8
JavadocToMarkdownDocCommentcomments out code on the same line (Keep code out of converted Markdown doc comments and escaped tags visible #1345)Details
- Where:
M/lang/JavadocToMarkdownDocComment.java:98-102. - Problem (CONFIRMED):
enum Color { /** Red */ RED, /** Green */ GREEN }becomes/// Redfollowed byRED, ...on the same line, so the code ends up inside the comment. - Also (SUSPECTED,
:813-825):<T>becomes a raw<T>, which renders as an invisible HTML tag.
- Where:
-
C9
DanglingDocCommentToBlockCommentnever converges on banner comments (Strip all leading asterisks inDanglingDocCommentToBlockComment(C9 of #1330) #1364)Details
- Where:
M/DanglingDocCommentToBlockComment.java:61-68, inUpgradeToJava25. - Problem (CONFIRMED): each pass strips one
*, so/******** section ********/keeps changing on every cycle. - Fix: strip the whole leading run of
*, or skip comments whose text starts with**.
- Where:
-
C10 Smaller
langitemsDetails
UseTextBlocks(SUSPECTED,:86-89): only Kotlin is excluded. In Groovy the result is a GString that interpolates$.MigrateClassNewInstanceToGetDeclaredConstructorNewInstance(SUSPECTED,:65-71):firstEnclosing(J.Try)also matches calls infinallyor resources. Constructor exceptions are now wrapped inInvocationTargetException, which the description doesn't mention.MigrateProcessWaitForDuration(SUSPECTED,:70-79):waitFor(Long.MAX_VALUE, DAYS)now throwsArithmeticException.MigrateSecurityManagerMulticast(SUSPECTED,:52-57): the dropped second argument may have side effects. It could also be a declarativeDeleteMethodArgument.ExtractExplicitConstructorInvocationArguments(SUSPECTED,:122-131,207-216): a nested type gets anOuter.Innerimport, and on a simple-name clash it binds to the wrong type. "Strictly behavior-preserving" over-claims.LiteralOrVariablehas no usages.
D. JDK API migrations (util, net, io, sql, logging, root)
-
D1
UseListOf/UseSetOf/UseMapOf: duplicates, nulls, foreign receiversDetails
- Where:
M/util/UseListOf.java,UseSetOf.javaandUseMapOf.java, reached viaJavaUtilAPIs→JavaBestPractices(A3). - Duplicates (CONFIRMED):
Set.of/Map.ofthrowIllegalArgumentExceptionon duplicate elements or keys, whereHashSetdeduplicates andHashMapkeeps the last write (UseSetOf:74-85,93-119,UseMapOf:72-99). - Runtime nulls (CONFIRMED): only literal
nullis excluded, solist.add(map.get(k))throws an NPE after migration (UseListOf:301-322,UseSetOf:245-266,UseMapOf:323-345). - Anonymous
{{ }}form (CONFIRMED):- The receiver isn't checked, so
other.add(x)is folded into the new list and the write tootheris lost (UseListOf:116-124,UseSetOf:100-107,UseMapOf:120-130). ArrayList<String> l = new ArrayList<>() {{..}}becomes= List.of(..), which doesn't compile.add(null)throws.
- The receiver isn't checked, so
- Related: Recipe UseMapOf generates Map.of() with nullable values or duplicate keys, causing runtime NullPointerException #1307 and UseMapOf: Skip refactoring large maps to Map.ofEntries to prevent javac compiler hangs (add maxEntries option) #1310.
- Where:
-
D2
Collections.*→List.of/Set.of/Map.of: undocumented semantic changesDetails
-
MigrateCollectionsEmpty{List,Map,Set}(:53-60):sort,removeIfandclearwere no-ops and now throw UOE;contains(null)now throws an NPE. -
MigrateCollectionsSingleton{List,Map,Set}: a runtime-null element now throws an NPE. -
MigrateCollectionsUnmodifiableSet(:56-71): anynew X(Arrays.asList(..))is accepted, soTreeSet/LinkedHashSetlose their order, duplicates throw, and{{ add(..) }}bodies are dropped. CONFIRMED. -
MigrateCollectionsUnmodifiableList(:52-68):unmodifiableList(asList(arr))was a live view ofarrand is now a copy.- There's no null check.
- The result keeps the zero-argument
List.of()method type.
CONFIRMED.
-
Fix: bail on these shapes, and state the null/mutability differences in the descriptions.
-
Related: Migrate unmodifiableMap(..) to Map.of(..) #71 asks for
unmodifiableMap(..)→Map.of(..); a new recipe would face the same null and duplicate-key hazards.
-
-
D3 Sequenced-collection recipes
Details
ListFirstAndLast(CONFIRMED,:76-96): on an empty list,get(0)threwIndexOutOfBoundsException, butgetFirst()throwsNoSuchElementException. Document it.StreamFindFirst(CONFIRMED,:57-58):- It NPEs on
stream()with an implicitthis. isOfClassType(SequencedCollection)is an exact match, soList/Dequereceivers never change. UseisAssignableTo.
- It NPEs on
- Stale types:
IteratorNext:60-64andStreamFindFirst:61-65clone the type ofiterator()/stream(), sogetFirst()returnsIterator<E>/Stream<E>. - YAML: the
SequencedCollectionrenames (Y/java-version-21.yml:97-117) have no Java 21 gate and lackmatchOverrides.
-
D4
ReplaceSystemOutWithIOPrintandMigrateStringReaderToReaderOfDetails
-
ReplaceSystemOutWithIOPrint(M/io/ReplaceSystemOutWithIOPrint.java:43-61, CONFIRMED):IOonly hasprint(Object)/println(Object), soprintln(char[])now prints[C@...- There's no Java 25 gate, so Kotlin modules capped at 24 get
IO.println, which doesn't exist there.
See also A1 and Bug and suggested fix.
ReplaceSystemOutWithIOPrintcorrupts syntax when method arguments have bounded or generic return types. #1304. -
MigrateStringReaderToReaderOf(CONFIRMED,:53-104): every nestednew StringReaderis rewritten, sowrap(new StringReader(s))withwrap(StringReader), or aSupplier<StringReader>lambda, no longer compiles.
-
-
D5
java.netrecipes (Keep the unsigned TTL insetTTLand thebytetype ingetTTLmigrations #1341)Details
MigrateMulticastSocketSetTTLToSetTimeToLive(CONFIRMED,:51-53): the recipe usesByte.valueOf(b).intValue(), which sign-extends, while the JDK usesByte.toUnsignedInt. SosetTTL((byte) 200)becomessetTimeToLive(-56), which throws IAE. The test atT/net/..SetTTL..Test.java:59asserts the wrong output. Fixed in Keep the unsigned TTL insetTTLand thebytetype ingetTTLmigrations #1341.MigrateMulticastSocketGetTTLToGetTimeToLive(CONFIRMED,Y/java-net-apis.yml:33-43):byte ttl = s.getTTL()becomes anintcall, which doesn't compile. Fixed in Keep the unsigned TTL insetTTLand thebytetype ingetTTLmigrations #1341.URLConstructorToURICreate(CONFIRMED,:76-83): the literal is validated after.trim(), butURIdoesn't trim, sonew URL(" https://x")throws at runtime after migration.URLConstructorsToNewURI(unwired,URLThreeArgumentConstructordoes not introduce newly thrown exception #467): it introduces a checkedURISyntaxException, encodes?in the file part, and usesURL.of(Java 20) without a gate.- URL encoder/decoder: the switch from the platform charset to UTF-8 is undocumented.
-
D6 Logging, SQL and Base64
Details
MigrateDriverManagerSetLogStream(CONFIRMED,:51-54):setLogStream(null), the usual way to turn logging off, becomesnew PrintWriter(null), which is ambiguous and doesn't compile.MigrateLoggerLogrbToUseResourceBundle(CONFIRMED,:51-60):ResourceBundle.getBundle(name)throwsMissingResourceException, where theStringoverload logged without localization.MigrateGetLoggingMXBeanToGetPlatformMXBean(CONFIRMED,:54-61): theChangeTypeonly runs in calling files, so standalone runs break call sites in other files. Move it togetRecipeList().MigrateLoggerGlobalToGetGlobal(SUSPECTED,:43): the template has a stray;, and the test relaxesmethodInvocations. Replace it withChangeStaticFieldToMethod.UseJavaUtilBase64(CONFIRMED JDK behaviour,:89-110): with the defaults,decodeBuffer→getDecoder()throws on line-wrapped input, andencodeBufferoutput changes for inputs over 57 bytes. Map these to the MIME coder.
-
D7 Exception-type swaps narrow the catch and break
throwsDetails
- Where:
M/ArrayStoreExceptionToTypeNotPresentException.java:52-58andM/IllegalArgumentExceptionToAlreadyConnectedException.java:52-58. - Problem (CONFIRMED): the catch type is replaced rather than widened, so other exceptions of the old type in the try body are no longer caught.
ChangeTypealso rewritesthrow new X("m", e)in the catch body, and neither new exception has that constructor. - Fix: use a multi-catch, changing only the parameter's type tree, and skip when the new type is already caught.
- Where:
-
D8 Root-package API recipes (Fix root-package API recipes reached by the Java 11 migration (D8 of #1330) #1366)
Details
-
ReferenceCloneMethod:69(CONFIRMED): passes the reference itself as the referent instead ofref.get(). ForWeakReference<String>the output doesn't compile. -
MXBeanRule:84-110(CONFIRMED): applies to any*MBeanclass once one non-public interface exists in the file.public interface FooMBeanbecomespublic public, and an abstract*MBeanclass losesabstract. -
ReplaceComSunAWTUtilitiesMethods:121,127-128(CONFIRMED):- An unchecked
(J.FieldAccess)cast throws on a static-imported constant. - The
superresult is discarded. - The template has no closing
).
The tests only use
com.test.*patterns, never the shipped defaults. - An unchecked
-
ReplaceAWTGetPeerMethod:76-78,112-114(CONFIRMED): resolves to the deprecated same-packageChangeMethodInvocationReturnType, whose visitor is a no-op, so the return type is never fixed. -
JREThrowableFinalMethods:93-107(SUSPECTED): also renames calls declared onjava.lang.Throwableitself. -
ChangeDefaultKeyStore(SUSPECTED, design):UsesJavaVersion(11,11)matches projects that have run on 11 for years, and hard-codes"jks". -
AddMissingMethodImplementation: anonymous classes are not visited. See alsoAddMissingMethodImplementationgenerates wrong method for constructors #360.
-
-
D9
RemovedSecurityManagerMethodsandRemovedSubjectMethodsDetails
-
M/RemovedSecurityManagerMethods.java:46-50(CONFIRMED):boolean b = sm.checkTopLevelWindow(w)becomes avoidcall.AllPermissionis far stronger than each original check.- There's no precondition and no test at all.
-
RemovedSubjectMethods(Y/java-version-21.yml:119-135, CONFIRMED no-op):- The zero-argument patterns never match
getSubject(AccessControlContext)ordoAs(Subject, ..). - Renaming alone wouldn't compile anyway (
callAstakes aCallable). - The display name has a stray backtick.
Delete it, or write a Java recipe.
- The zero-argument patterns never match
-
-
D10
SimplifyMicrometerMeterTagsproduces broken codeDetails
- Where:
M/metrics/SimplifyMicrometerMeterTags.java:45-66. It is unwired and has no precondition. - Problem (CONFIRMED):
.tags("k", "v")becomes.tag("k"[0], "k"[1]).- With four or more tags, only the first pair is kept.
tags(new String[0])is renamed and no longer compiles.
- Fix: fix it and move it to rewrite-micrometer, or delete it.
- Where:
E. Guava
-
E1
NoGuavaJava11:ImmutableSet/ImmutableMap→Set.of/Map.ofchange runtime behaviourDetails
- Where:
M/guava/AbstractNoGuavaImmutableOf.java:93-130andY/no-guava.yml:104-109. - Problem (CONFIRMED, JDK spec):
Set.of(a, b)throws IAE whena.equals(b); Guava deduplicates.- The iteration order of
Set.of/Map.of/copyOfis unspecified and randomized per JVM, while Guava keeps insertion order. JSON key order,toStringand test assertions change. contains(null)/get(null)throw an NPE on all JDK immutables, includingList.of.
- Fix: make the Set and Map conversions opt-in, or limit them to distinct compile-time constants, and document the null-query difference.
- Where:
-
E2
AbstractNoGuavaImmutableOfcrashes and wrong targetsDetails
- Varargs (CONFIRMED,
:202-225):getParameterTypes().get(index)throwsIndexOutOfBoundsExceptionwhen the call is a vararg argument, for exampleString.format("%s %s", "a", ImmutableList.of("b"))or SLF4Jlog.info(..). - Lambdas (CONFIRMED,
:193-201): areturninside a lambda is checked against the enclosing method's return type. - Select branch (CONFIRMED,
:208-209):ImmutableSet.of(..).asList()becomesSet.of(..).asList(). - SUSPECTED:
- The rewritten call keeps the
ImmutableList.ofmethod type. ImmutableList.of(arr)gives a one-element list, whileList.of(arr)spreads the array.convertReturnType=trueretypes variables that still use Guava-only API.
- The rewritten call keeps the
- Metadata:
getShortType(:71-73) renders descriptions as "Replaces.common.collect.ImmutableList.of(..)" (visible inrecipes.csv:147-152).
- Varargs (CONFIRMED,
-
E3
NoGuavaemits Java 9–16 APIs with no version gateDetails
- Problem (CONFIRMED): run on a Java 8 project, these produce code that doesn't compile:
NoGuavaIterablesAnyFilter:69:Stream.toList()(16).NoGuavaOptionalAsSet:52:Optional.stream()(9).Predicates.not→Predicate.not(Y/no-guava.yml:205-207, 11).InlineGuavaMethods:repeat(Y/inline-guava-33-methods.yml:228, 11) andoptional.stream()(:89-107).- Picnic
InputStreamRulesRecipes(Y/no-guava.yml:86):transferTo,readAllBytesand others.
- Optional on Java 8 (CONFIRMED,
Y/no-guava.yml:184-186):or(Optional)is renamed toorElse(Optional), becausePreferJavaUtilOptionalOrSupplieronly runs on 9+. Narrow the pattern toor(java.lang.Object). - Fix: move these into
NoGuavaJava11/NoGuavaJava21, or addUsesJavaVersionpreconditions.
- Problem (CONFIRMED): run on a Java 8 project, these produce code that doesn't compile:
-
E4
PreferCharComparetargetsjava.lang.Char(RewriteChars.comparetoCharacter.compareinstead of nonexistentChar.compare#1333)Details
- Where:
Y/no-guava.yml:306-318. - Problem (CONFIRMED):
java.lang.Chardoesn't exist, soChars.compare(a, b)becomesChar.compare(a, b)when run standalone. InsideNoGuava,InlineGuavaMethods(Y/inline-guava-33-methods.yml:136) rewrites the call first, which hides the bug. - Fix: use
java.lang.Character, or delete it together with the other duplicates ofInlineGuavaMethods(PreferInteger/Long/ShortCompare,PreferMath*Exact). Add a test.
- Where:
-
E5
Function/Supplier/Optional/Predicatetype swaps leave Guava consumers brokenDetails
-
Unconditional swaps (CONFIRMED,
Y/no-guava.yml:145-157,160-192,211-223): theChangeTypes apply unconditionally.- Consumers break:
Lists.transform(l, F),Maps.transformValues,Futures.transformandSuppliers.memoizenow getjava.util.functiontypes. - Producers break:
Iterables.tryFindandEnums.getIfPresentstill return a GuavaOptional.
Reuse the "file uses such an API" exclusion from
NoGuavaPredicate. - Consumers break:
-
Predicates (CONFIRMED):
NoGuavaPredicatesAndOr:95-101,NoGuavaPredicatesEqualTo:70-78andPredicates.notproduce ajava.util.function.Predicateregardless ofNoGuavaPredicate's exclusion.NoGuavaPredicatesAndOrTest:53-59andNoGuavaFunctionsComposeTest:61-79expect output that doesn't compile.NoGuavaPredicatesEqualTo:70-71builds its type witness fromtoString(), givingPredicate.<int>isEqual(5).
-
NoGuavaPredicate:66,74-79: the precondition only matches a Predicate in the last parameter, and it checks per file. -
Related:
PreferJavaUtilFunctionshould not convert when used specifically as Guava type #436, and NoGuava Recipe – Summary of the analysis on the Sirius-Desktop codebase #928, whose Sirius-Desktop analysis collects many of these shapes (plus some from E2 and E6).
-
-
E6 Smaller Guava bugs
Details
NoGuavaPrimitiveAsList:59-64(CONFIRMED):Ints.asList(intArray)becomesList<int[]>, andLongs.asList(1, 2)becomesList<Integer>.NoGuavaCreateTempDir:65-77(CONFIRMED): calls inside lambdas, or inside thecatch/finallyof a try that catchesIOException, are converted and leave an unhandledIOException.NoGuavaSetsFilter:59(CONFIRMED):toCollection(TreeSet::new)drops the comparator. Also see@ExpectedToFailatT/guava/NoGuavaSetsFilterTest.java:106.NoMapsAndSetsWithExpectedSize:64-91(CONFIRMED): gated on Java 19, but it emitsnew HashMap<>(n)(capacity) instead ofHashMap.newHashMap(n).NoGuavaRefaster:76-79(CONFIRMED): static-importsString.valueOf, which is shadowed inside enums.PreferJavaUtilOptional(CONFIRMED):get()now throwsNoSuchElementExceptioninstead ofIllegalStateException, and staticOptional.toJavaUtil(x)isn't handled.NoGuavaDirectExecutor:50-56(SUSPECTED): no guard for.execute(r)orvarusage.PreferJavaStringJoinVisitor:64-69(SUSPECTED): the template lacks its closing).JoinerNPEs on null elements, whileString.joinprints"null".- Lazy views become eager copies (
Collections2.transform,Iterables.filter,Sets.filter). This is undocumented. - Springfox bump (
Y/no-guava.yml:33-37, SUSPECTED): check whether 2.10.x removed@EnableSwagger2. PreferJavaUtilObjectsEquals(CONFIRMED by probe,Y/no-guava.yml:227-240): in a class with its ownequals(Object), the static import ofObjects.equalsis shadowed, soequals(a, b)doesn't compile. See PreferJavaUtilObjectsEquals does not check for existing equals method #434.
F. Lombok
-
F1
UseLombokSetterdeletes setters that do more than assign the parameter (Keep setters that do more than assign their parameter inUseLombokSetter#1332)Details
- Where:
M/lombok/LombokUtils.java:122-178. - Problem (CONFIRMED):
isSetterchecks the name, owner and parameter type, but never the right-hand side.this.name = name.trim(),this.items = new ArrayList<>(items)andthis.x = 5are all replaced by a plain@Setter, so the logic is lost silently. - Fix: require the assigned value to be a
J.Identifierreferring to the method's own parameter.
- Where:
-
F2
boolean isFoofields: wrong setter nameDetails
- Where:
M/lombok/LombokUtils.java:180-182,214-216. - Problem (CONFIRMED): Lombok generates
setFoofor a primitiveboolean isFoo, but the recipes expectsetIsFoo.UseLombokSetterdeletessetIsFooand callers break;AdoptLombokSetterMethodNamesrenames a correctsetFootosetIsFoo. - Fix: mirror Lombok's
toSetterName. - Related: Lombok replaces uppercase getter method with generated camelCase, breaking existing code. #879.
- Where:
-
F3
AdoptLombok{Getter,Setter}MethodNamesrename methods that aren't accessorsDetails
- Where:
M/lombok/LombokUtils.java:93-108,184-212. - Problem (CONFIRMED): any identifier or field access is accepted, including static constants, other objects' fields, enum constants and outer-class fields. So
String version() { return VERSION; }becomesgetVERSION(), andownerName() { return owner.name; }becomesgetName(). - Fix: reuse the owner, non-static and
this.-only checks fromisGetter/isSetter.
- Where:
-
F4 Constructor recipes drop annotations
Details
UseRequiredArgsConstructor/UseAllArgsConstructor(CONFIRMED,M/lombok/LombokUtils.java:282-335): parameter annotations andthrowsare ignored, soS(@Qualifier("primary") Foo foo)becomes@RequiredArgsConstructorand the qualifier is lost.UseNoArgsConstructor(CONFIRMED,:47-70): drops constructor annotations (@Inject,@JsonCreator,@Deprecated), comments in the body (A() { // for JPA }), andthrows.- SUSPECTED:
- Varargs parameters (
:313) produce anA(String[])constructor. - Non-Lombok
@NonNullannotations (:235-258) change Lombok's set of required fields, so callers break.
- Varargs parameters (
-
F5
FieldAnnotatorkeeps an existing@Getter/@Setterand its access levelDetails
- Where:
M/lombok/FieldAnnotator.java:49-71. - Problem (CONFIRMED): with
@Getter(AccessLevel.PROTECTED) int foo; public int getFoo(), the public getter is deleted and the getter becomes protected. In a multi-variable declaration, the first accessor's access level wins for every variable. - Fix: bail in both cases.
- Where:
-
F6
LombokBestPracticesbreaks modules without Lombok, and Java 8 projectsDetails
- No dependency check (CONFIRMED,
Y/lombok.yml:17-48): there's noModuleHasDependency org.projectlombok:lombokprecondition and nothing adds the dependency, so non-Lombok modules get Lombok annotations that don't compile. The standaloneUseLombok*andUse*ArgsConstructorrecipes behave the same. - Java 8 (CONFIRMED,
Y/lombok.yml:27,M/lombok/LombokValToFinalVar.java:53-60):UpdateLombokToJava11runsval→final varwith no Java 10 gate. - Fix: add the dependency precondition and a
HasJavaVersiongate. See also A1 and B7.
- No dependency check (CONFIRMED,
-
F7
UseLombokLogAnnotations: nested classes and name clashesDetails
- Nested classes (CONFIRMED,
M/lombok/log/LogVisitor.java:48-64): converting a logger in a nested class also annotates every enclosing class. If one of them is an interface, it doesn't compile. - Name clash (CONFIRMED,
:97-99): the field is renamed tologwithout a clash check, soLOGGER.info(log)with alogparameter breaks. - SUSPECTED:
lombok.configkeys are never read:lombok.log.fieldName,lombok.accessors.*,lombok.getter.noIsPrefix.- The plain
JavaIsoVisitors also hit Groovy and Kotlin. synchronizedgetters,throwsclauses and Javadoc on removed methods are dropped.
- Nested classes (CONFIRMED,
-
F8
LombokValueToRecordDetails
extends(CONFIRMED,:110-117):@Value class A extends Bbecomesrecord A(..) extends B.- Arrays (CONFIRMED,
:190-202,315-332): array fields lose Lombok's deepequals/hashCode/toString. toStringformat: withoutuseExactToString,A(a=1)becomesA[a=1].- Stale types (
:229-236,334-340): call sites renamed tox()keep the method type, and the record's class type is replaced by an emptyShallowClass. - Description: should warn that getter call sites and
toStringchange.
G. Jakarta EE / Java EE / JPA / JSpecify
-
G1
HttpSessionInvalidatereplacessession.invalidate()withrequest.logout()(KeepHttpSession.invalidate()when addingHttpServletRequest.logout()#1334)Details
- Where:
M/javax/HttpSessionInvalidate.java:51-75, reached by everyJavaxMigrationToJakartarun viajavaee8→javaee7→javaee6(Y/java-ee-6.yml:28). - Problem (CONFIRMED): the description says "Add …
logout", but the code replacesinvalidate().logout()clears authentication but leaves the session alive, so logout and reset handlers silently stop invalidating sessions. That is a security regression.logout()also throws the checkedServletException.T/javaee/HttpSessionInvalidateTest.java:39-55encodes the replacement. - Also:
- NPE when there's no enclosing method declaration, or its type is missing (
:53-54,83). - The precondition
or(UsesMethod, UsesType(HttpServletRequest))lets every servlet file through.
- NPE when there's no enclosing method declaration, or its type is missing (
- Fix: keep
invalidate()and addlogout()before it only whenServletExceptionis handled, or make the recipe search-only.
- Where:
-
G2 OpenJPA → EclipseLink recipes annotate the wrong elements and crash
Details
AddTransientAnnotationToCollections:57-75(CONFIRMED): parameters and locals get@Transient, which has@Target({METHOD, FIELD}). It NPEs on untyped lambda parameters (:59) and unresolved annotations (:64).AddTransientAnnotationToEntity:85-107(CONFIRMED): no enclosing-class check, so fields, parameters and locals of entity type in services and DTOs get@Transient. It also has the same NPE.AddTableGenerator:71-81(CONFIRMED): on getter-annotated entities,@GeneratedValue(strategy = IDENTITY)becomesTABLEwithout a@TableGenerator.AddTransientAnnotationToPrivateAccessor:84-90(CONFIRMED): NPEs on a private no-arg constructor.classVars(:54-66) is clobbered by nested classes.RemoveTemporalAnnotation:96(CONFIRMED): NPEs on lambda parameters.AddDefaultConstructorToEntityClass:47-58(CONFIRMED): addspublic X() {}to entities that have no constructor, and acts on outer classes of nested entities.RemoveEmbeddableId:113-116(SUSPECTED): unchecked(JavaType.Class)cast.
-
G3
RemoveBeanIsNullablecleans up the whole fileDetails
- Where:
M/jakarta/RemoveBeanIsNullable.java:47-51. - Problem (CONFIRMED):
RemoveUnusedLocalVariablesandSimplifyConstantIfBranchExecutionrun on the whole compilation unit, which deletes unrelated code. Also:foo(bean.isNullable())becomesfoo( false).- A select with side effects is dropped.
- Where:
-
G4
UpdateGetRealPathmisses nested calls (Rewrite nested and unqualifiedgetRealPath(String)calls for Servlet 6 #1339)Details
- Where:
M/jakarta/UpdateGetRealPath.java:41-51. - Problem (CONFIRMED): there's no
supercall, soPaths.get(req.getRealPath("/"))is never migrated and fails on Servlet 6. - Also (SUSPECTED): with no select, as in a
HttpServletRequestWrappersubclass,nullis passed to#{any()}.
- Where:
-
G5
BeanDiscovery,JpaCachePropertiesandAddStaticVariableOnProducerSessionBeanDetails
BeanDiscovery:67-72(CONFIRMED, test encodes it): an explicitbean-discovery-mode="none"or"annotated"is overwritten with"all". Keep an explicit mode.JpaCacheProperties:93-102(CONFIRMED):versionis read from<persistence-unit>, so it is always null. JPA 1.0 files get a<shared-cache-mode>their schema forbids, and the EclipseLink branch (:157-179) is dead. SUSPECTED: every unit getsNONE, including Hibernate apps, which silently disables@Cacheable.AddStaticVariableOnProducerSessionBean:81-101(CONFIRMED dead): it only matchesjakartatypes, but runs injavaee7onjavaxcode. If it did fire, a static@Produces @PersistenceContextfield would break.
-
G6
WsWsocServerContainerDeprecationnever renames insideJakartaEE10Details
- Where:
Y/jakarta-ee-10.yml:201-214, run afterJavaxMigrationToJakarta(:27vs:34). - Problem (CONFIRMED): the method pattern names the
javax.servletparameters, which have already been renamed. TheChangeTypestill applies, givingServerContainer.doUpgrade(..), which doesn't exist. The standalone test passes. - Fix: use
doUpgrade(..). Even then,upgradeHttpToWebSocketis an instance method, so the change needs a TODO comment or a Java recipe.
- Where:
-
G7 Faces 3
FindAndReplaceturns XML into plain text, so the Faces 4 updates are skippedDetails
- Where:
Y/jakarta-faces-3.yml:126-129(faces-config),:154-157(taglib) and:182-189(web-fragment), versusY/jakarta-faces-4.yml:141,161,181. - Problem (CONFIRMED by tracing): any file containing
javax.becomes aPlainText, and the laterChangeTagAttributeversion andschemaLocationupdates skip it, so these files stay at 3.0/5.0 underJakartaEE10/11. - Fix:
web.xmlwas already moved toChangeTagValue; do the same for these three. - Probe:
JakartaEE10on a 2.3 faces-config with<el-resolver>javax.el.BeanELResolver</el-resolver>.
- Where:
-
G8
MigrateFastjsonForJakarta10: swapped enums and a non-recursive package change (Map fastjson features to the right fastjson2 enum and migrate@JSONFieldimports #1342)Details
- Where:
Y/jakarta-ee-10.yml:866-874. - Problem (CONFIRMED):
SerializerFeaturemaps toJSONReader.Featureandparser.FeaturetoJSONWriter.Feature, the wrong way round.ChangePackage com.alibaba.fastjsonisn't recursive, soannotation.JSONFieldkeeps the old package after the dependency swap.
- Also: it has no tests. See also A6.
- Where:
-
G9 CDI and JSF recipes
Details
AddScopeToInjectedClass/AnnotateTypesVisitor(CONFIRMED, unwired):- It adds
@Dependentto classes that already have a scope (a CDIDefinitionException), and to interfaces and abstract classes. - It throws
ClassCastExceptionon@Inject T t.
- It adds
UpdateManagedBeanToNamed:56-79(SUSPECTED): an unscoped@ManagedBeanis request-scoped, but an unscoped@Namedis@Dependent.eager = trueis dropped. Add@RequestScoped. See also FacesManagedBeansRemoved for Faces 4.0 recipe updates #1023.JacksonProviderOverrides:45-46: targets_configForWriting(ObjectMapper, Annotation[]), which nojackson-jaxrs-basesince 2.3 has. The test stub models a shape that doesn't exist. Delete it, or test against the real jar.AddApiDependencyForImports:89-92(SUSPECTED): JSR-305javax.annotation.Nullableimports addjakarta.annotation-api.
-
G10 JSpecify migrations invert array nullness and keep invalid attributes
Details
MoveAnnotationToArrayType:62,95(CONFIRMED from the parser):public @Nullable String[] f()is aJ.AnnotatedTypeand is skipped. The laterChangeTypethen flips "nullable array" into "nullable elements".Y/jspecify.yml:114-115(CONFIRMED viajavap): the comment claims Jakarta's@Nullabletargets TYPE_USE, but it has no@Target, so Jakarta arrays get the same inversion.- Attributes (CONFIRMED,
Y/jspecify.yml:78-93,146-153,236-243):ChangeTypekeeps them, and none compile on JSpecify: JetBrains@NotNull("msg"), Micronaut@Nullable(inherited = ..), javax@Nonnull(when = ..).when = MAYBEreally means nullable. @ParametersAreNonnullByDefault→@NullMarked(:90-93, SUSPECTED):@NullMarkedalso covers returns and fields.- See also B8.
H. Search recipes & data tables
-
H1
AboutJavaVersionreports the target as the source version (FixAboutJavaVersionsource version and per-run dedup (H1 of #1330) #1365)Details
- Where:
M/search/AboutJavaVersion.java:75. - Problem (CONFIRMED): the source-compatibility column uses
getMajorReleaseVersion(); it should usegetMajorVersion(). The test uses equal source and target, so it can't catch this. - Also: the
transient Set seenSourceSetsfield (:39) is shared across runs.
- Where:
-
H2 DTO and javax search recipes
Details
-
DontOverfetchDto(CONFIRMED,M/DontOverfetchDto.java:60-145):- Signatures change without updating callers.
- Uses like
feed(dog)/return dogare left dangling. dog.getName()can become an unboundname.- The test's
TypeValidation.none()hides an inlinedjava.lang.StringFQN.
Restrict it to private methods, make it search-only, or delete it.
-
FindDataUsedOnDto:51-57(CONFIRMED): nosupercall, sodto.getAddress().getCity()records only the outer call. -
FindDtoOverfetching:53-83(SUSPECTED): uses of all DTO parameters are merged, and DTOs passed on whole are still flagged. -
FindInternalJavaxApis:58-80(SUSPECTED): reports JDK-onlyjavaxAPIs (Cipher,javax.sql,javax.swing). -
FindJavaVersion:57/PlanJavaMigration:51:preVisitwithoutstopAfterPreVisit()walks every node.
-
I. Type attribution & TypeValidation.none()
-
I1 Keep method types in sync (Keep method types in sync with renamed and rebuilt calls (I1 of #1330) #1351)
Details
IteratorNext:60-64,StreamFindFirst:61-65(D3).MigrateCollectionsUnmodifiableList:52-68(keeps the zero-argumentList.of()type).AbstractNoGuavaImmutableOf:124-128.PreferJavaUtilOptionalOrElseNull(withSimpleName).NoGuavaPredicatesInstanceOf:55-71: hand-built member reference with null types.LombokValueToRecord:229-236,334-340.ReplaceAWTGetPeerMethod(D8).StringFormatted:77-80: picks any member namedformatted.- Six more
withSimpleNamerenames inM/util,M/netandM/logging(see the triage notes).
-
I2 Remove
TypeValidation.none()where it hides recipe bugs (RemoveTypeValidationrelaxations that hid recipe bugs (I2 of #1330) #1348)Details
- Scope: 17
none()and 5 partial relaxations. - Hides a recipe bug:
T/DontOverfetchDtoTest:33. Fixed in RemoveTypeValidationrelaxations that hid recipe bugs (I2 of #1330) #1348.T/guava/NoGuavaPredicatesInstanceOfTest:41. Fixed in RemoveTypeValidationrelaxations that hid recipe bugs (I2 of #1330) #1348.T/logging/MigrateLoggerGlobalToGetGlobalTest:39. This was stale, not a recipe bug. Fixed in RemoveTypeValidationrelaxations that hid recipe bugs (I2 of #1330) #1348.
- Stale:
T/util/UseLocaleOfTest:40, whose FIXME is about "not Java 19". Fixed in RemoveTypeValidationrelaxations that hid recipe bugs (I2 of #1330) #1348. - Gate on the JRE instead:
T/util/MigrateStringReaderToReaderOfTest:35andT/io/ReplaceSystemOutWithIOPrintTest:34should use@EnabledForJreRange(min = JAVA_25), since CI runs 25. Fixed in RemoveTypeValidationrelaxations that hid recipe bugs (I2 of #1330) #1348; this exposed a wrongIO.println(Object)type inReplaceSystemOutWithIOPrint. - Fix the classpath:
T/lombok/LombokValueToRecordTest:426needsjackson-annotations. Fixed in RemoveTypeValidationrelaxations that hid recipe bugs (I2 of #1330) #1348.T/lombok/LombokValToFinalVarTest:198-311needs the Lombok classpath. Fixed in RemoveTypeValidationrelaxations that hid recipe bugs (I2 of #1330) #1348.
- Legitimate (missing-type subject), so keep:
IfElseIfConstructToSwitchTest:1072,1103,LombokOnXToOnX_Test:33, the JAXB/annotation no-change tests inT/jakarta, andAddJaxbApiForUnattributedImportsTest.
- Scope: 17
J. Preconditions & declarative
-
J1 Add preconditions (Add missing preconditions and Java version gates to recipes (J1) #1349)
Details
- Root package:
RemovedSecurityManagerMethods:37,ReplaceComSunAWTUtilitiesMethods:110,ReplaceLocalizedStreamMethods:62. jakarta:ApplicationPathWildcardNoLongerAccepted:38,InvocationContextGetConstructor:39,JacksonProviderOverrides:43,JerseyLoggingFilterToFeature:36,JettyConnectorGetPort:38,RemoveBeanIsNullable:43,UpdateAddAnnotatedTypes:35,UpdateBeanManagerMethods:41,UpdateGetRealPath:36,UpdateAnnotationAttributeJavaxToJakarta:46.lang:MigrateClassLoaderDefineClass:44,ThreadStopUnsupported:47.metrics:SimplifyMicrometerMeterTags:44.- DTO recipes:
DontOverfetchDto:59,FindDataUsedOnDto:45,FindDtoOverfetching:47(UsesTypefrom the option). - Edit visitor only:
AddTransientAnnotationToEntity:85. - Lombok: the five
Use*Logrecipes (UsesMethod(factoryMethodPattern)). - Java version:
MigrateProcessWaitForDuration:44(addUsesMethod),ReplaceSystemOutWithIOPrint,OptionalStreamRecipe,JavaConcurrentAPIs(Java 9).
- Root package:
-
J2
UsesType→UsesMethod(MATCHER)reusing the visitor's own matcher (UseUsesMethodpreconditions with the visitors' own matchers (J2) #1346)Details
net/URLConstructorsToNewURI:46net/URLConstructorToURICreate:55nio/file/RedundantUtf8Charset:60util/RemoveFinalizerFromZip:55-57JREThrowableFinalMethods:63:UsesType<>("java.lang.Throwable", true)matches nearly every file.guava/AbstractNoGuavaImmutableOf:91HttpSessionInvalidate:44-47: alreadyUsesMethodsince KeepHttpSession.invalidate()when addingHttpServletRequest.logout()#1334.
Fixed in Use
UsesMethodpreconditions with the visitors' own matchers (J2) #1346. -
J3 Replace
isAcceptablewith preconditions (UseJavaFileCheckerprecondition inExtractExplicitConstructorInvocationArguments#1337)Details
M/lang/ExtractExplicitConstructorInvocationArguments.java:67: usenot(KotlinFileChecker)andnot(GroovyFileChecker), asSwitchCaseReturnsToSwitchExpressiondoes.
-
J4 Make it declarative (Make
java.net/logging/langand Guava factory recipes declarative (J4) #1350)Details
M/net/MigrateHttpURLConnectionHttpServerErrorToHttpInternalError.java→ReplaceConstantWithAnotherConstant. This also removes an unconditionaldoAfterVisit.M/logging/MigrateLoggerGlobalToGetGlobal.java→ChangeStaticFieldToMethod.M/lang/MigrateSecurityManagerMulticast.java→DeleteMethodArgument, if side effects are acceptable (C10).- Guava Refaster candidates: the
Lists/Maps/Setsfactory recipes,NoGuavaIterablesAll,NoGuavaCollections2Transform. - Compatibility: keep the recipe names as YAML recipes so existing references don't break.
K. Mechanical polish (low risk, good first issues)
Items K1–K12 are in the first comment below, to keep this issue under GitHub's size limit.
L. Open questions & coverage
-
L1 Decide where
Singletongoes before polishingDetails
- Status: 257
Singletonpreconditions; 212 are on non-top recipes. - Why it matters: the non-top ones currently dedupe the diamond includes (Faces 2→3 reached four times; see A5). Remove the diamonds before stripping them.
- Also: the DataNucleus files (
Y/datanucleus-*.yml:19) have none, not even on their top recipes.
- Status: 257
-
L2 Test what ships
Details
- Status: 120 of 292 YAML recipes are loaded by name in a test. All but 2 of the rest sit under a tested composite, but those composite tests rarely exercise the sub-recipes.
- No test at all:
RemovedSecurityManagerMethodsAddJDeprScanPluginAddSuppressionForIllegalReflectionWarningsPluginPlanJavaMigrationInlineGuavaMethods(79 entries)PreferChar/Integer/Long/ShortComparePreferMath*ExactPreferJavaUtilFunction/SupplierPreferJavaNioCharsetStandardCharsetsopenJPAToEclipseLink
- Highest-value gaps:
- the confirmed bugs in E4, B8, G6, G7, G8 and D9
- Lombok on Gradle (B7)
UpgradeToJava25on a Kotlin 1.x module (B2, D4)- the Java 25
AccessController/RemoveSecurityPolicy/RemoveSecurityManagerrecipes, which also runUnnecessaryCatch/UnnecessaryThrowsfile-wide UpdateApacheCommonsEmailDependenciesNoGuavawithjavaVersion(8)(E3)
- Not testing the shipped defaults:
ReplaceComSunAWTUtilitiesMethodsTest:30andReplaceAWTGetPeerMethodTest:30usecom.test.*patterns. - Tests that assert wrong output: TTL (D5), Micrometer (D10),
HttpSessionInvalidate(G1),BeanDiscovery(G5),AddLombokMapstructBinding(B1), and the expected outputs listed in E5 that don't compile.
-
L3 Verify upstream before fixing
Details
- GraalVM (B10): which
resource-config.jsonformat accepts globs? - Kotlin (B2): confirm the maximum
jvmTargetper Kotlin version. - Docker (B3): which
eclipse-temurinvariants exist for 25? - Springfox (E6): does 2.10.x drop
@EnableSwagger2? RemovedSecurityManagerMethods: were these removed in JDK 10 or deprecated in 11? The description says 11.
- GraalVM (B10): which
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsBacklog
Activity
timtebeek commentedon Oct 24, 2026
Continued from the issue body.
K. Mechanical polish (low risk, good first issues)
K1 Typed
#{any(..)}placeholders instead of#{any()}Details
ReplaceComSunAWTUtilitiesMethods:138-163,jakarta/UpdateGetRealPath:43,lang/MigrateClassNewInstanceToGetDeclaredConstructorNewInstance:70.guava/NoMapsAndSetsWithExpectedSize:64,73,82,91util/UsePredicateNot:68util/MigrateCollectionsSingletonSet:57io/ReplaceSystemOutWithIOPrint:60logging/MigrateLoggerLogrbToUseResourceBundle:52jakarta/JettyConnectorGetPort:41util/UseSetOf:78,109UseListOf:93,125UseMapOf:83-86,132-135MigrateCollectionsUnmodifiableSet:66UseEnumSetOf:102MigrateCollectionsSingletonMap:62guava/NoGuavaSetsNewHashSet:79NoGuavaPrimitiveAsList:59AbstractNoGuavaImmutableOf:113,116langare legitimately untyped; leave them.K2 Drop forced imports, and
contextSensitive()where it isn't needed (Drop forced imports and unneededcontextSensitive()fromJavaTemplaterecipes #1347)Details
ReplaceComSunAWTUtilitiesMethods:125,126net/MigrateURLDecoderDecode:60net/MigrateURLEncoderEncode:61-63(AddImport(.., false), with a "not sure why" comment)contextSensitive():UseJavaUtilBase64:129ReferenceCloneMethod:73MigrateClassLoaderDefineClass:46, which also holds itsJavaTemplatein a fieldK3 Remove
//noinspectionlinesDetails
JpaCacheProperties:131AddMockitoJavaAgentToMavenSurefirePlugin:157,166UseJavaUtilBase64:118net/URLConstructorToURICreate:159search/FindInternalJavaxApis:64javax/AnnotateTypesVisitor:46jspecify/MoveAnnotationToArrayType:80,113K4
private static final UPPER_SNAKEmatchers and FQNs; no per-visit allocation (Hoist visitor matchers and regexes intoprivate static finalconstants (K4 of #1330) #1357)Details
RemovedSecurityManagerMethods:39-42jakarta/JerseyLoggingFilterToFeature:38-41UpdateAddAnnotatedTypes:37UpdateBeanManagerMethods:43-44UpdateGetRealPath:38JettyConnectorGetPort:40JacksonProviderOverrides:45javax/AddTableGenerator:48-49AddScopeToInjectedClass:62JREThrowableFinalMethods:68AddMockitoJavaAgentToMavenSurefirePlugin:73getVisitor():util/OptionalNotEmptyToIsPresent:46(also misnamed)OptionalNotPresentToIsEmpty:46javax/HttpSessionInvalidate:42-43search/FindInternalJavaxApis:58javax/RemoveTemporalAnnotation:65-67ArrayStoreExceptionToTypeNotPresentException:44IllegalArgumentExceptionToAlreadyConnectedException:44lombok/LombokUtils:247PatterninUpgradeDockerImageVersion:197andUpdateSdkMan:92javax/UseJoinColumnForMapping:33-34.net/URLConstructorsToNewURI:34-36URLConstructorToURICreate:45util/OptionalStreamRecipe:39-42guava/NoGuavaCreateTempDir:49ReplaceLocalizedStreamMethods:64K5 Use the
Commentstrait instead of hand-built comments (Use theCommentstrait instead of hand-built comments (K5 of #1330) #1355)Details
org.openrewrite.trait.Comments, incubating since 8.86. It is idempotent and supportsPlacement.FIRST_CHILD.lang/ThreadStopUnsupported:68-76CommentJava24KotlinCap:122-150(Xml.Commentplus hand-rolledhasCapComment/removeCapComment)io/AddInputStreamBulkReadMethod:102: emits a transientSearchResult. A TODO comment would persist.K6
ListUtils,JavaIsoVisitor,assertand restating comments (UseListUtils,JavaIsoVisitorand null checks, drop restating comments (K6 of #1330) #1356)Details
ListUtils.filter:lombok/LombokValueToRecord:354-359MXBeanRule:104-108JavaIsoVisitor:AddStaticVariableOnProducerSessionBean:82MXBeanRule:56,67jakarta/UpdateGetRealPath:37assertin recipe code:ReplaceAWTGetPeerMethod:79,115lombok/AdoptLombok{Getter,Setter}MethodNames:104LombokValueToRecord:97,335guava/PreferJavaStringJoinVisitor:59search/ModuleHasKotlinSource:76lang/var/UseVarForConstructors:31-39search/FindLocaleDateTimeFormats:33-45MigrateGraalVMResourceConfig:36-60jakarta/UpgradeMavenEjbPluginConfiguration:27-35AddJDeprScanPlugin:28-31AddSuppressionForIllegalReflectionWarningsPlugin:29-32UpgradeJavaVersion:65-69LombokUtils(about 17)MigrateGraalVMResourceConfigHttpSessionInvalidateRemoveTemporalAnnotationAddColumnAnnotationUseVarForGenericMethodInvocations:137,141MigrateMainMethodToInstanceMain:95,106,120@Option:JREThrowableFinalMethods:41-48,UseJavaUtilBase64:36(sunPackage).K7 Java display names and descriptions (Polish Java recipe display names and descriptions (K7 of #1330) #1359)
Details
@Slf4instead of@Slf4j:lombok/log/UseSlf4j:31,36.UseLogRecipeTemplate:31.SecurityManager":RemovedSecurityManagerMethods:29.util/RemoveFinalizerFromZip:46.@Inject':AddScopeToInjectedClass:39.UpdateAddAnnotatedTypes:32.\n:AddColumnAnnotation:40-43.EnumSet of(..):UseEnumSetOf:51.java.lang.Char: E4.PreferJavaUtilOptionalOrSupplier:41.AddMockitoJavaAgentToMavenSurefirePlugin:61AddJDeprScanPlugin:41AddSuppressionForIllegalReflectionWarningsPlugin:48AddSurefireFailsafeArgLine:44LombokValueToRecord:55SwitchCaseAssignmentsToSwitchExpression:43UseVarForGenericsConstructors:37UpdateSdkMan:66("SDKMAN!")MXBeanRule:48javax/Add*/Remove*JPA recipesIfElseIfConstructToSwitch:50OptionalStreamRecipe:34UpdateGetRealPath:30AddMissingMethodImplementation:53AddStaticVariableOnProducerSessionBean:41BeanDiscovery:38InvocationContextGetConstructor:33,36HttpSessionInvalidate:36MigrateGraalVMResourceConfig:63AddSurefireFailsafeArgLine:46ChangeDefaultKeyStore:41IllegalArgumentExceptionToAlreadyConnectedException:40AddJakartaXmlBindRuntime:45HttpSessionInvalidate:38says "Add".AddJaxbRuntime:66-70names the wrong scopes.ApplicationPathWildcardNoLongerAccepted:32says "trailing slash".RemoveBeanIsNullable:38contradicts itself.NoMapsAndSetsWithExpectedSizesays "Java 19+ methods".StringFormatted:44-47option text.UseVarForGenericMethodInvocations:40-41says "open rewrite cannot handle them correctly ATM".ThreadStopUnsupported:42-44has a dangling " .".ReplaceComSunAWTUtilitiesMethods:35-76share one display name, as do the two inReplaceLocalizedStreamMethods:34-44.AboutJavaVersion:41has no display name.UpdateAnnotationAttributeJavaxToJakarta:37-43:signatureisrequired = falsebut NPEs when null.K8 YAML display names and descriptions (Polish YAML recipe display names and descriptions (K8 of #1330) #1360)
Details
Y/lombok.yml:19)Y/java-version-25.yml:73,94,115)jakarta-ee-10/11,jakarta-faces-4/41andjava-ee-8JavaxXmlToJakartaXmlXJCBinding)DeprecatedCDIAPIsRemoved40)Y/java-virtual-threads.yml:42)Y/jakarta-ee-10.yml:333,Y/java-version-17.yml:292)Y/java-version-21.yml:121)Y/java-lang-var.yml:22-23)ApacheDefaultProvidersays "Flags", but it rewrites.JakartaEE11says "flagging".MigrateZipErrorToZipExceptionsays "Java 9 or higher", but it is gated on 25.AddJaxwsDependencies(Y/java-version-11.yml:140) mentionsjavax.xml.bind.NoGuavaJava11/NoGuavaJava21have copy-pasted descriptions.UseVarAddLombokMapstructBindingMavenDependencyOnly(Y/java-version-17.yml:388)UpgradeBuildToJava24ForKotlin1xAddAspectJToolsToAspectJMavenPluginUpdate*Dependenciesrecipes in the Jakarta and Faces filesMigrateFrom*inY/jspecify.ymlUpdateRestLet2_6openJPAToEclipseLinkandjavaee6/7/8start lowercase.BounceCastleFromJdk15OntoJdk18Onis a typo (Y/bouncycastle-jdk18on.yml:19).K9 YAML options at their default value (Drop YAML options set to their default value (K9 of #1330) #1354)
Details
acceptTransitive: false(Y/java-version-17.yml:375,399)recursive: false(Y/bouncycastle-jdk18on.yml:318,Y/ibm-java.yml:116,Y/jakarta-ee-9.yml:905; at:158keep the comment and drop the option)addParentheses: true(Y/java-best-practices.yml:47)onlyIfVersionsMatch: true(Y/jaxb-apis.yml:43,47,138).newVersion: 1.18.*→1.18.x(Y/lombok.yml:63).K10 Move tests to their recipe's package, and name them after it (Move tests to their recipe's package and name them after it (K10 of #1330) #1358)
Details
T/javaee/AddTableGeneratorTestandHttpSessionInvalidateTest→javaxT/javaee/ApacheDefaultProviderTestandServletIsRequestedSessionIdFromURLTest→javaee8T/javaee/OpenJPAPersistenceProviderTest→javaee7T/lang/MigrateZipErrorToZipExceptionTest→ rootT/maven/MigrateJaxwsMavenPluginTest→javaxT/guava/NoGuavaPredicatesEqualToTestandNoGuavaSetsFilterTestrunNoGuavaT/jakarta/JakartaXmlBindRuntimeTestT/jakarta/UpdateAnnotationAttributeJavaxToJakartaTestrunsJakartaEE10T/UpgradeSpringBootForJava25TestT/util/MigrateInflaterDeflaterToAutoCloseableTestT/lang/UseThreadsOrExecutorsTestrunsFindVirtualThreadOpportunitiesT/lang/var/UseVarForObjectsTestT/lombok/log/ConvertToLogAnnotationTestEnvironment.builder()/scanRuntimeClasspathinstead ofrecipeFromResources:UseVarKeywordTest,JavaLangAPIsTest,PreferJavaUtilOptionalTest(which also has two@DocumentExamples).K11 Stale
@Disabled/@ExpectedToFailand demo tests (Resolve stale@Disabledand demo tests (K11 of #1330) #1353)Details
T/lang/var/UseVarForObjectsTest:313: Skipvarreplacement when the type cannot fully be resolved #608 was closed by skipping static methods, so turn this into a no-change test.T/lang/UseTextBlocksTest:659textBlockDemo: delete it.T/lang/UseVarKeywordTest:216andUseVarForObjectsTest:118: convert to no-change tests.T/lombok/LombokOnXToOnX_Test:188: "Parser bug with @__ syntax". Re-check against the current parser.T/lang/UseTextBlocksTest:971: redundantexpectedCyclesThatMakeChanges(0).K12 Remove deprecated recipes at the next major
Details
M/ChangeMethodInvocationReturnType.java(fix D8 first)M/ReplaceStringLiteralValue.javaM/RemoveIllegalSemicolons.java(after A5)M/maven/UpdateMavenProjectPropertyJavaVersion.javaM/maven/UseMavenCompilerPluginReleaseConfiguration.javatimtebeek commentedon Oct 24, 2026
Fixes for the items in "Start here" are up for review:
HttpSessionInvalidate: KeepHttpSession.invalidate()when addingHttpServletRequest.logout()#1334AddLombokMapstructBinding: Keep Lombok running whenAddLombokMapstructBindingcreatesannotationProcessorPaths#1335UseLombokSetter: Keep setters that do more than assign their parameter inUseLombokSetter#1332IfElseIfConstructToSwitch: Leave if-else-if chains alone when a switch would change behaviour or not compile #1336NullCheckAsSwitchCase: Do not drop theelsebranch when merging a null check into a switch #1331PreferCharCompare: RewriteChars.comparetoCharacter.compareinstead of nonexistentChar.compare#1333Two corrections from working on them:
UpgradeToJava17,EnableLombokAnnotationProcessorruns first and already adds a Lombok processor path, so the build only broke whenAddLombokMapstructBindingran on its own. In the composite, the old behaviour mostly left the Lombok path at1.18.40instead of the project's version.One new finding for B7: when
EnableLombokAnnotationProcessorcreates<annotationProcessorPaths>, any other processors that javac used to pick up from the classpath (for examplehibernate-jpamodelgen) stop running as well. Not addressed in #1335.Use `UsesMethod` preconditions with the visitors' own matchers (#1346)
Remove `TypeValidation` relaxations that hid recipe bugs (I2 of #1330) (
Keep method types in sync with renamed and rebuilt calls (I1 of #1330) (
Drop pinned patch versions when upgrading Docker image tags (B3 of #1330
Resolve stale `@Disabled` and demo tests (K11 of #1330) (#1353)
Drop YAML options set to their default value (K9 of #1330) (#1354)
Use the `Comments` trait instead of hand-built comments (K5 of #1330) (…
Use `ListUtils`, `JavaIsoVisitor` and null checks, drop restating com…
Move tests to their recipe's package and name them after it (K10 of #…
Polish YAML recipe display names and descriptions (K8 of #1330) (#1360)
Hoist visitor matchers and regexes into `private static final` consta…
Polish Java recipe display names and descriptions (K7 of #1330) (#1359)
Fix `AboutJavaVersion` source version and per-run dedup (H1 of #1330) (…
Fix root-package API recipes reached by the Java 11 migration (D8 of #…
melloware commentedon Oct 29, 2026
@timtebeek i posted on the Discord channel and got no response. I am having the hardest time using the Code Genome repo and i have a proper token and key but still getting 403's trying to run recipes. Can you have someone in support monitor the Discord channel?
timtebeek commentedon Oct 29, 2026
Sorry to hear! We're definitely more active on Slack if that's an option for you; in short you'll need a token to download the Apache licensed modules; we do not provide free downloads of the MSAL modules on our infra, as we found these were often used well beyond what the license allows. They remain source available, and within the terms (not sold as a service for instance), you can build these modules and run the recipes all the same. It's a few more steps unfortunately. The order can be seen on https://openrewrite.github.io/rewrite-recipe-bom/ , with build instructions on https://docs.openrewrite.org/reference/building-openrewrite-from-source. 🙏🏻
You're the second one today expressing difficulty despite familiarity with the project, so we're also taking another look at our docs & process. 🤞🏻
melloware commentedon Oct 29, 2026
thanks @timtebeek yeah the docs make it sound like just get a token change settings.xml and it will just work and it definitely does not for the JDK25 Recipe which is where I got the instructions in the first place.
RojanFrancis commentedon Nov 4, 2026
Hi @timtebeek, I've opened fixes for two items on this list: C5 (
ThreadStopUnsupported) in #1411 and C3 (SwitchCaseAssignmentsToSwitchExpression) in #1413. Both are ready for review once CI is approved. Thanks!