
本文介绍在使用 OpenRewrite(如 UpgradeToJava17 等迁移配方)时,如何安全排除 Collections.singletonMap 等不兼容 null 键的 API 替换,避免单元测试因 Map.of() 不支持 null 键而失败。
本文介绍在使用 openrewrite(如 `upgradetojava17` 等迁移配方)时,如何安全排除 `collections.singletonmap` 等不兼容 `null` 键的 api 替换,避免单元测试因 `map.of()` 不支持 `null` 键而失败。
OpenRewrite 在执行 Java 版本升级(如 org.openrewrite.java.migrate.UpgradeToJava17)时,会默认将 Collections.singletonMap(null, "v") 等调用替换为 Map.of(null, "v")。但 Map.of() 明确禁止 null 键或值,导致原有依赖 null 键行为的单元测试直接抛出 NullPointerException——这正是你遇到的问题。
✅ 推荐方案:升级 rewrite-migrate-java 至 v2.0.7+
自 v2.0.7 起,Collections.singletonMap 相关替换规则已被从默认 Java 8→11/17 迁移配方中移除(参见 PR #253),从根本上规避该问题。升级后无需手动排除,即可保留 singletonMap 原始调用:
<!-- Maven pom.xml --> <dependency><groupid>org.openrewrite.recipe</groupid><artifactid>rewrite-migrate-java</artifactid><version>2.0.7</version><!-- 或更高稳定版 --></dependency>
⚠️ 若必须使用旧版本或需精细控制,可显式配置 exclusions:
-
Maven 插件配置示例(跳过指定类/方法):
<plugin><groupid>org.openrewrite.maven</groupid><artifactid>rewrite-maven-plugin</artifactid><configuration><activerecipes><recipe>org.openrewrite.java.migrate.UpgradeToJava17</recipe></activerecipes><exclusions><!-- 排除所有 singletonMap 调用 --><exclusion>java.util.Collections#singletonMap(..)</exclusion><!-- 或更精确:仅排除含 null 键的调用(需自定义 Recipe 支持) --></exclusions></configuration></plugin>
-
Gradle 配置示例:
rewrite { activeRecipe("org.openrewrite.java.migrate.UpgradeToJava17") exclusions = [ "java.util.Collections#singletonMap(..)" ] }
? 注意事项:
-
exclusions使用 OpenRewrite 的 MethodMatcher 语法,格式为包名.类名#方法名(参数类型...);..表示任意参数。 - 排除粒度为方法调用级别,无法按「是否含
null参数」动态判断(此逻辑需自定义 Recipe 实现)。 - 建议优先升级依赖而非依赖排除——既减少维护成本,又确保与社区最佳实践同步。
总结:面对 Map.of() 与 null 键兼容性问题,升级 rewrite-migrate-java 是最简洁、可持续的解决方案;仅在特殊场景下才需启用 exclusions 配置,并务必验证排除范围是否精准覆盖所有风险调用点。










