What version of OpenRewrite are you using?
- org.openrewrite:rewrite-core:8.85.4
- org.openrewrite.recipe:rewrite-migrate-java:3.37.0
What is the smallest, simplest way to reproduce the problem?
UseMapOf rewrites the initializer of a variable to Map.of(..) but does not touch the variable's declared type. When the variable is declared with the concrete type java.util.HashMap (rather than the Map interface), the result no longer compiles: Map.of(..) returns an immutable java.util.Map, which is not assignable to a HashMap variable.
This only reproduces for a field — as a local variable the value tends to be inlined, and the declared type disappears.
@Test
void useMapOfLeavesIncompatibleHashMapDeclaredType() {
rewriteRun(
spec -> spec.recipe(new UseMapOf()),
// language=java
java(
"""
package com.helloworld;
import java.util.HashMap;
class Main {
private static final HashMap<String, String> VALUES =
new HashMap<String, String>() {
{
put("key", "value");
}
};
}
""",
spec -> spec.markers(javaVersion(25))));
}
What did you see instead?
The recipe rewrites only the initializer and leaves the declared type as HashMap:
import java.util.HashMap;
+import java.util.Map;
class Main {
- private static final HashMap<String, String> VALUES =
- new HashMap<String, String>() {
- {
- put("key", "value");
- }
- };
+ private static final HashMap<String, String> VALUES = Map.of("key", "value");
}
The rewritten source does not compile:
incompatible types: java.util.Map<java.lang.String,java.lang.String>
cannot be converted to java.util.HashMap<java.lang.String,java.lang.String>
We hit this on a real test class during a batch run of the conventions recipes, and it had to be repaired by hand.
What did you expect to see?
Either:
-
The recipe also widens the declared type to Map<String, String>, producing compilable code:
private static final Map<String, String> VALUES = Map.of("key", "value");
...or
-
The recipe skips the rewrite when the declared type is a concrete subtype (HashMap, LinkedHashMap, ...) that would not accept the Map.of(..) result.
What version of OpenRewrite are you using?
What is the smallest, simplest way to reproduce the problem?
UseMapOfrewrites the initializer of a variable toMap.of(..)but does not touch the variable's declared type. When the variable is declared with the concrete typejava.util.HashMap(rather than theMapinterface), the result no longer compiles:Map.of(..)returns an immutablejava.util.Map, which is not assignable to aHashMapvariable.This only reproduces for a field — as a local variable the value tends to be inlined, and the declared type disappears.
What did you see instead?
The recipe rewrites only the initializer and leaves the declared type as
HashMap:The rewritten source does not compile:
We hit this on a real test class during a batch run of the conventions recipes, and it had to be repaired by hand.
What did you expect to see?
Either:
The recipe also widens the declared type to
Map<String, String>, producing compilable code:...or
The recipe skips the rewrite when the declared type is a concrete subtype (
HashMap,LinkedHashMap, ...) that would not accept theMap.of(..)result.