Skip to content

Skip UseMapOf when the anonymous HashMap is assigned to a concrete HashMap variable - #1149

Merged
timtebeek merged 1 commit into
mainfrom
tim/usemapof-widen-hashmap-1148
Jun 25, 2026
Merged

timtebeek merged 1 commit into
mainfrom
tim/usemapof-widen-hashmap-1148

Conversation

@timtebeek

@timtebeek timtebeek commented Jun 25, 2026

Copy link
Copy Markdown
Member

Fixes #1148

Problem

For the anonymous-class form, UseMapOf replaced new HashMap<>() {{ put(..); }} with an immutable Map.of(..) but left the declared type untouched. When the variable was declared with the concrete type HashMap (rather than the Map interface), the result no longer compiled, since Map.of(..) returns an immutable java.util.Map that is not assignable to a HashMap variable:

private static final HashMap<String, String> VALUES = new HashMap<>() {{ put("key", "value"); }};
// became uncompilable:
private static final HashMap<String, String> VALUES = Map.of("key", "value");

Fix

Skip the anonymous-class rewrite when its result is assigned to a variable whose declared type is the concrete HashMap rather than the Map interface (option 2 in the issue). Beyond the assignability problem, widening the declared type to Map would also risk breaking later calls to HashMap-specific methods, so leaving such declarations untouched is the safer behaviour.

The guard checks the enclosing variable's declared type straight off the NamedVariable:

private boolean isAssignedToConcreteHashMap() {
    Object parent = getCursor().getParentTreeCursor().getValue();
    return parent instanceof J.VariableDeclarations.NamedVariable &&
            TypeUtils.isOfClassType(((J.VariableDeclarations.NamedVariable) parent).getType(), "java.util.HashMap");
}

The common cases — assigning to a Map-typed variable, returning, or using the value inline — are unaffected and still rewrite to Map.of(..). The mutable prose form (new HashMap<>(); x.put(..)new HashMap<>(Map.of(..))) already stays a HashMap and so was never affected.

Tests

Added field and local-variable cases asserting that a concrete HashMap declaration is left unchanged (the field case mirrors the issue's reproducer with javaVersion(25)). Existing tests — including the Map-interface, LinkedHashMap/TreeMap, null-bail, and prose-form cases — continue to pass.

@github-project-automation github-project-automation Bot moved this to In Progress in OpenRewrite Jun 25, 2026
@timtebeek
timtebeek force-pushed the tim/usemapof-widen-hashmap-1148 branch from b80a19b to cb3243d Compare June 25, 2026 11:32
@timtebeek timtebeek changed the title Widen concrete HashMap declared type when UseMapOf rewrites it to Map.of(..) Skip UseMapOf rewrite when the assignment target is a concrete HashMap Jun 25, 2026
@timtebeek
timtebeek force-pushed the tim/usemapof-widen-hashmap-1148 branch from cb3243d to 1251368 Compare June 25, 2026 11:43
@timtebeek timtebeek changed the title Skip UseMapOf rewrite when the assignment target is a concrete HashMap Skip UseMapOf when the anonymous HashMap is assigned to a concrete HashMap variable Jun 25, 2026
@timtebeek
timtebeek merged commit b6c9ae6 into main Jun 25, 2026
1 check passed
@github-project-automation github-project-automation Bot moved this from In Progress to Done in OpenRewrite Jun 25, 2026
@timtebeek
timtebeek deleted the tim/usemapof-widen-hashmap-1148 branch June 25, 2026 12:37
mergify Bot added a commit to robfrank/linklift that referenced this pull request Jul 17, 2026
…37.0 to 3.40.0 [skip ci]

Bumps [org.openrewrite.recipe:rewrite-migrate-java](https://github.com/openrewrite/rewrite-migrate-java) from 3.37.0 to 3.40.0.
Release notes

*Sourced from [org.openrewrite.recipe:rewrite-migrate-java's releases](https://github.com/openrewrite/rewrite-migrate-java/releases).*

> 3.40.0
> ------
>
> What's Changed
> --------------
>
> * Keep `\t` and `\f` escapes in UseTextBlocks to avoid incidental whitespace stripping by [`@​timtebeek`](https://github.com/timtebeek) in [openrewrite/rewrite-migrate-java#1160](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1160)
> * Skip UseEnumSetOf empty conversion for static fields to avoid circular class-init ([#1157](https://redirect.github.com/openrewrite/rewrite-migrate-java/issues/1157)) by [`@​timtebeek`](https://github.com/timtebeek) in [openrewrite/rewrite-migrate-java#1161](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1161)
> * Skip `UseMapOf` for `LinkedHashMap`/`TreeMap` in the prose `put()` form ([#1163](https://redirect.github.com/openrewrite/rewrite-migrate-java/issues/1163)) by [`@​timtebeek`](https://github.com/timtebeek) in [openrewrite/rewrite-migrate-java#1165](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1165)
> * Skip AddMockitoJavaAgentToMavenSurefirePlugin when agent already configured in build/plugins by [`@​timtebeek`](https://github.com/timtebeek) in [openrewrite/rewrite-migrate-java#1166](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1166)
> * Add RedundantUtf8Charset recipe to drop redundant UTF-8 from Files calls by [`@​timtebeek`](https://github.com/timtebeek) in [openrewrite/rewrite-migrate-java#1167](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1167)
> * Fix Jakarta EE 10 web.xml migration by [`@​sakshichitnis27`](https://github.com/sakshichitnis27) in [openrewrite/rewrite-migrate-java#1159](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1159)
>
> New Contributors
> ----------------
>
> * [`@​sakshichitnis27`](https://github.com/sakshichitnis27) made their first contribution in [openrewrite/rewrite-migrate-java#1159](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1159)
>
> **Full Changelog**: <openrewrite/rewrite-migrate-java@v3.39.0...v3.40.0>
>
> 3.39.0
> ------
>
> What's Changed
> --------------
>
> * Make ExtractExplicitConstructorInvocationArguments templates context-free by [`@​knutwannheden`](https://github.com/knutwannheden) in [openrewrite/rewrite-migrate-java#1140](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1140)
> * Convert Javadoc `<br>` tags to Markdown line breaks by [`@​timtebeek`](https://github.com/timtebeek) in [openrewrite/rewrite-migrate-java#1142](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1142)
> * Preserve angle brackets when converting `@param <T>` to Markdown by [`@​timtebeek`](https://github.com/timtebeek) in [openrewrite/rewrite-migrate-java#1141](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1141)
> * Fix JavadocToMarkdown's handling of varargs and JDKs newer than the bytecode source/target compatibility by [`@​sambsnyd`](https://github.com/sambsnyd) in [openrewrite/rewrite-migrate-java#1143](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1143)
> * Move ReplaceUnusedVariablesWithUnderscore to Java best practices by [`@​timtebeek`](https://github.com/timtebeek) in [openrewrite/rewrite-migrate-java#1144](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1144)
> * Extend Use{List,Set,Map}Of to recognise prose-statement chains by [`@​steve-aom-elliott`](https://github.com/steve-aom-elliott) in [openrewrite/rewrite-migrate-java#1145](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1145)
> * Skip `UseMapOf` when the anonymous `HashMap` is assigned to a concrete `HashMap` variable by [`@​timtebeek`](https://github.com/timtebeek) in [openrewrite/rewrite-migrate-java#1149](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1149)
> * Fix jakarta.enterprise.concurrent-api version for EE9 and EE10 by [`@​evie-lau`](https://github.com/evie-lau) in [openrewrite/rewrite-migrate-java#1152](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1152)
> * Add recipe to replace jakarta jws-api with ws-api in EE10 by [`@​evie-lau`](https://github.com/evie-lau) in [openrewrite/rewrite-migrate-java#1151](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1151)
> * Upgrade maven-ejb-plugin alongside jakarta.ejb-api by [`@​evie-lau`](https://github.com/evie-lau) in [openrewrite/rewrite-migrate-java#1155](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1155)
> * Upgrade maven-ear-plugin for ee9 and ee11 by [`@​evie-lau`](https://github.com/evie-lau) in [openrewrite/rewrite-migrate-java#1156](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1156)
>
> **Full Changelog**: <openrewrite/rewrite-migrate-java@v3.38.0...v3.39.0>
>
> v3.38.0
> -------
>
> What's Changed
> --------------
>
> * use . instead # for FQN link in Markdown javadoc by [`@​barbulescu`](https://github.com/barbulescu) in [openrewrite/rewrite-migrate-java#1134](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1134)
> * Bump maven-pmd-plugin to 3.28.x for Java 25 support by [`@​timtebeek`](https://github.com/timtebeek) in [openrewrite/rewrite-migrate-java#1136](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1136)
> * Explain why Kotlin modules are capped at Java 24 during Java 25 migration by [`@​timtebeek`](https://github.com/timtebeek) in [openrewrite/rewrite-migrate-java#1137](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1137)
> * Preserve `@{argLine}` in AddSurefireFailsafeArgLine for JaCoCo coverage by [`@​timtebeek`](https://github.com/timtebeek) in [openrewrite/rewrite-migrate-java#1138](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1138)
> * Add recipe to extract complex explicit constructor invocation arguments (JEP 513) by [`@​timtebeek`](https://github.com/timtebeek) in [openrewrite/rewrite-migrate-java#1135](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1135)
> * Bump Kotlin 2.0-2.2 to 2.3 so Kotlin modules can reach Java 25 by [`@​timtebeek`](https://github.com/timtebeek) in [openrewrite/rewrite-migrate-java#1139](https://redirect.github.com/openrewrite/rewrite-migrate-java/pull/1139)
>
> **Full Changelog**: <openrewrite/rewrite-migrate-java@v3.37.0...v3.38.0>


Commits

* [`6584812`](openrewrite/rewrite-migrate-java@6584812) Fix Jakarta EE 10 web.xml migration ([#1159](https://redirect.github.com/openrewrite/rewrite-migrate-java/issues/1159))
* [`3d0ad8f`](openrewrite/rewrite-migrate-java@3d0ad8f) OpenRewrite recipe best practices
* [`76925b9`](openrewrite/rewrite-migrate-java@76925b9) Add RedundantUtf8Charset recipe to drop redundant UTF-8 from Files calls ([#1167](https://redirect.github.com/openrewrite/rewrite-migrate-java/issues/1167))
* [`c0d0f67`](openrewrite/rewrite-migrate-java@c0d0f67) Skip AddMockitoJavaAgentToMavenSurefirePlugin when agent already configured i...
* [`12386c8`](openrewrite/rewrite-migrate-java@12386c8) Skip UseMapOf for LinkedHashMap/TreeMap in prose put-statement form ([#1163](https://redirect.github.com/openrewrite/rewrite-migrate-java/issues/1163)) (...
* [`ee2f4c4`](openrewrite/rewrite-migrate-java@ee2f4c4) OpenRewrite recipe best practices
* [`5f18964`](openrewrite/rewrite-migrate-java@5f18964) Skip UseEnumSetOf empty conversion for static fields to avoid circular class-...
* [`4cd2123`](openrewrite/rewrite-migrate-java@4cd2123) Keep \t and \f escapes in UseTextBlocks to avoid incidental whitespace stripp...
* [`16e662d`](openrewrite/rewrite-migrate-java@16e662d) Upgrade maven-ear-plugin for ee9 and ee11 ([#1156](https://redirect.github.com/openrewrite/rewrite-migrate-java/issues/1156))
* [`b9f0360`](openrewrite/rewrite-migrate-java@b9f0360) Upgrade maven-ejb-plugin alongside jakarta.ejb-api ([#1155](https://redirect.github.com/openrewrite/rewrite-migrate-java/issues/1155))
* Additional commits viewable in [compare view](openrewrite/rewrite-migrate-java@v3.37.0...v3.40.0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

UseMapOf rewrites the initializer of a HashMap-typed variable to Map.of(), leaving uncompilable code

1 participant