关于 rust-java-migration
面向将 Java 项目迁移到 Rust 的团队,提供保留行为、映射源码结构和审计兼容性的指导。强调按批次推进、明确基线、建立清单及以证据验证。
主要功能
- 01Java 到 Rust 迁移流程
- 02包到模块的路径映射
- 03Crate 边界与工作区规划
- 04源码和测试清单
- 05布局审计与兼容性证据
适用场景
- 01规划完整项目或模块迁移
- 02继续现有 Rust 移植工作
- 03审计行为和 API 兼容性
- 04组织迁移测试与文档
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ full-stack-skills/ rust-skills --skill rust-java-migration安装后在 Claude Code 中输入/rust-java-migration确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
agents/openai.yamlassets/templates/对象名称一致性检查.md对象级对照表.md语义迁移对照表.md迁移路线图.mdexamples/golden-migration/Cargo.lockCargo.tomlexamples/golden-migration/src/agent_state_store.rsagent_state.rsin_memory_agent_state_store.rslib.rsstate_error.rsexamples/golden-migration/tests/state_store.rsreferences/case-study-lessons.mdcodegraph-parity-audit.mdcomment-migration.mdcompile-drift-and-cleanup.mdcomponent-candidate-catalog.mdcomponent-replacement-sop.mdcrate-replacement-discovery.mdcross-language-migration-profile.mddirectory-path-alignment.mdlayout-and-governance.mdrust-api-adaptation.mdsemantic-mappings.mdverification-and-acceptance.mdscripts/audit_migration_layout.pyscaffold_migration_docs.pyscripts/tests/test_audit_migration_layout.pytest_scaffold_migration_docs.py详细介绍
Java 到 Rust 迁移
迁移契约和可观察行为,而不是 Java 语法。保留 Java 项目的公共概念和源代码可追溯性,同时选择 Rust 原生的所有权、错误处理、并发、异步、序列化和框架机制。
强制迁移布局
- 根据声明的包根目录之后的 Java 包路径推导 Rust 目录;保留有意义的嵌套包,绝不扁平化、错置或重复嵌套。
- 将 Java 对象名称转换为考虑首字母缩写的
snake_case.rs;Rust 类型保留PascalCase,不要添加_trait等后缀。 - 一个 Java 对象对应一个 Rust 对象边界。Rust 没有通用的文件长度限制:将最多 500 行物理行视为正常;对 501–800 行进行内聚性审查;禁止编写超过 800 行的
.rs文件。 - 仅当文件混合了不同职责时才拆分。保留一个主要对象文件,并使用从属文件承载内聚的实现系列,且不要引入第二个迁移对象;记录每次拆分或经审查的例外。
lib.rs和mod.rs仅保留声明和重新导出。移动文件后更新父模块,并使用::限定有歧义的外部重新导出。- 有用时,在
#[cfg(test)]模块中保留针对私有行为的单元测试。将公共边界、跨模块、差异、宿主和整个项目的测试放在tests/或非发布的<project>-test包中;将源代码夹具放在<project>-test/tests/fixtures/。
阅读目录路径对齐和布局与治理,然后在移动文件后运行布局审计。
范围与路由
将此技能用于完整项目迁移、单个 Maven/Gradle 模块迁移、兼容性审计、迁移规划,或继续现有 Rust 移植。
这是跨语言迁移规范的 Rust 适配器。将 crate/布局/API、依赖项、宏和领域机制路由到对应的 Rust 技能。将验证路由到 rust-java-migration-testing 及相关测试技能。
如果用户只要求审计、计划或文档,则不要修改迁移代码。仅规划或只读请求不授权运行会生成文件的文档脚手架工具:在回复中提供拟议的四份文档内容、使用 --dry-run,或仅写入用户批准的目标位置。未经授权,不要将模块迁移扩大为整个仓库的重写。
必需输入
解决或明确标记未知项:
- Java 仓库路径、基线提交或标签、构建工具、JDK 和模块范围。
- 用于路径映射的确切 Java 模块包根目录;不要只传入仓库根目录或
src/main/java根目录,然后猜测要去掉哪些路径段。 - Rust 仓库路径、基线提交、工具链/MSRV、工作区和目标平台。
- 目标产品拓扑输入:独立发布的 Rust 单元、依赖/功能/目标/过程宏/FFI 边界、预期 crate 数量、包系列、根目录噪声、其他语言和既定路径。
- 兼容性目标:源代码形态一致、公共 API 一致、行为一致,还是生产环境替代。
- 依赖策略:许可证、MSRV、支持的目标平台、不安全代码策略、公告策略、维护期限和可接受的传递依赖成本。
- 组件候选来源及其观察日期;区分团队策略、调研候选项、已声明的依赖项和已验证的采用情况。
- 明确的例外、受阻的外部项目、不支持的仅限 JVM 功能和完成期限。
- 必需的宿主应用、真实脚本、测试数据、并发模型、负载配置和回滚机制。
- 现有迁移文档及其权威性;在合并历史材料前,先确定唯一一套当前的四份文档。
- 完整的源代码测试根目录/运行器配置,包括每个具体测试用例、已禁用的测试、测试夹具、脚本、语料库、黄金文件、资源和数据文件。源仓库定义分母;不要为了适配 Rust 而缩小范围。
绝不要在未说明的情况下推断,最新分支、生成的清单或 API 注册列表就是行为基线。
工作流
默认将一个已声明的 Java 源模块及其对应的 Rust 目标 crate/模块作为一个迁移批次。经用户授权的多模块范围可以作为一个批次,但必须在实施前冻结边界。按以下顺序执行:冻结范围/契约 → 实施该批次 → 冻结 → 审计 → 统一验证。
允许在实施批次中按依赖顺序编辑。不允许按对象逐个循环完成。
1. 冻结基线并检查仓库状态
记录两个仓库的 SHA、工作区是否有未提交更改、Java/Rust 工具链、模块清单、启用的功能和生成代码边界。保留现有 Rust 工作和无关更改。
验证 Rust 工具链满足工作区 MSRV:默认的旧版 rustc 会因 rustc X is not supported by the following packages 而失败——使用 rustup run <ver> cargo ... 运行检查门禁,绝不要暗中降低 rust-version。
如果仓库包含 .codegraph/,请在文本搜索或逐文件阅读前使用 CodeGraph:
- 调查模块/包/crate 架构。
- 查询具有代表性的公共类型和重载方法。
- 沿高价值调用链进行追踪,涵盖工厂、注册表、拦截器、序列化器、持久化、网络和并发。
- 查询对应的 Rust 代码及其调用方/测试。
- 如果索引报告已过时,则在实施前刷新模块清单或重新查询。
如果不存在索引,未经授权不得初始化。使用语言感知工具或有针对性的源码检查,并说明证据较弱。
阅读 CodeGraph 对等审计,了解查询模式和清单规则。 在设计大型工具库迁移或注解/宏拆分时,阅读 案例经验。
1.5. 推导 Rust crate 边界和工作区拓扑
不要将 Maven/Gradle 模块与 Cargo package 一一对应。应根据独立发布/复用、依赖/功能/目标隔离、proc-macro 或 FFI 约束以及不同的生命周期来划分 Rust package;源代码模块仍作为可追溯范围。
使用 rust-workspace 选择布局:规模较小且内聚的项目通常采用根目录扁平布局;存在实际的适配器/绑定/示例/测试系列时适合采用混合布局;大型、根目录内容繁杂或多语言仓库可能适合使用 crates/。数量仅用于触发审查,并非硬性规定。在路线图中记录源代码模块到 crate 的映射、所选拓扑、被否决的方案以及兼容性计划。参见布局与治理。
2. 在实施前建立清单
为以下内容分别创建机器可读或表格形式的清单:
- Java Maven/Gradle 模块和 Rust crate。
- 源代码模块到 crate 的映射,以及说明根目录扁平布局、混合布局或分组收纳路径为何适合本项目。
- Java package 和 Rust 模块目录。
- 类、接口、枚举、记录、注解、异常以及相关的内部类型。
- 每个对象在移除组织/module package 根路径并保留剩余部分中最后两个片段后(不足两个时保留一个或零个)的确定性 Rust 路径。
- 公有/受保护构造函数和方法,包括所有重载。
- 参数名称、顺序、泛型约束、可空性、默认值、可变参数、受检异常和返回值约定。
- 现有对象、构造函数、方法、泛型/值参数、返回值、异常、元数据标签和语义性内联注释,并注明源代码锚点。
- 示例、测试、测试夹具、脚本、配置、资源、服务描述符和文档。
- 源测试用例清单和资源清单;在将资源逐字节复制到 Rust 之前,记录每个具体用例和资源路径/哈希。
- 一个不发布的
<project>-testpackage,负责项目级源代码重放、跨组件路径和差异验收。 - 调用路径和可从外部观察到的副作用。
只有通过显式分类,才能排除 package-info、生成的源代码、BOM、聚合器、测试支持、门面和仅供 Rust 使用的基础设施。不要通过更改分母来隐去它们。
在修改生产代码前,将清单冻结为批次清单。覆盖完整分母、依赖顺序、共享机制、组件决策、测试处置和获批的例外;不要逐个对象发现工作范围。
从此 SKILL.md 确定 SKILL_DIR;绝不要假设固定的安装路径。从 Rust 迁移根目录运行命令,并优先使用相对于仓库的输入/产物路径。
尽早运行 Rust 静态布局审计,作为初步信号:
python3 "$SKILL_DIR/scripts/audit_migration_layout.py" \
--java-package-root ../java-project/source-module/src/main/java/org/example/module \
--rust-root . \
--retain-segments 2 \
--require-source-comments \
--fail-on-warning
该脚本会计算预期路径,并区分缺失对象与位置错误的对象。它还会检测非 snake_case 路径、包含多个对象的文件、门面定义、通配符导入、存根宏/恐慌、空函数体以及缺少中文源代码注释的情况。对于获批的 501–800 行内聚性审查,使用重复的 --reviewed-large-file path/to/file.rs 记录;这不会豁免超过 800 行的文件。任何严格阻断项都会使迁移无法完成;即使扫描结果干净,也不能证明 Java/Rust 语义一致。
3. 为每个源模块创建四份文档
获得编写文档的授权后,在实现之前为每个 Java 模块生成一个文档目录:
python3 "$SKILL_DIR/scripts/scaffold_migration_docs.py" \
--module source-module \
--java-root ../java-project/source-module \
--java-package-root ../java-project/source-module/src/main/java/org/example/module \
--rust-root <selected-target-crate-or-workspace> \
--output-dir docs/source-module \
--java-baseline <sha-or-tag> \
--rust-baseline <sha> \
--retain-segments 2
该命令会创建:
迁移路线图.md— 范围、基线、阶段、依赖项、风险和证据关卡。对象级对照表.md— 每个 Java 对象及其对应的 Rust 文件/类型/状态。语义迁移对照表.md— 每类行为及其 Rust 原生实现。对象名称一致性检查.md— 数量、缺失/额外/合并的对象、名称、方法、参数和逻辑缺口。
根据源代码证据填充所有占位内容。生成的模板属于 DRAFT,不构成证据,也绝不代表已完成。代码变更时同步更新文档。模板:
四份文档均须独立详尽,并包含模块当前的迁移约定:源代码/Rust SHA、精确对象分母、目标根目录、retain_segments = 2、状态快照、严格完成规则,以及该文档的职责。拒绝只有标题、只有数量或只有占位内容的文档。为防止内容流于摘要,至少要求三个有实质内容的二级章节,以及一个证据表或任务矩阵;使用仓库配置的篇幅下限(默认 45 个非空行),但对于确实很小的模块,生成的对象表可以按比例缩短。
每份文档都必须分别列出 Java 和 Rust 基线、最近审计日期及文档状态。每条已迁移/已验证的记录都需要证据锚点:源文件或符号、目标文件或符号、测试/判定基准、精确命令,以及适用时的产物。实现期间,不要逐条升级记录状态。批次冻结后,根据当前 Rust SHA 交叉核对全部四份文档,并在一次集中的更新中修改状态。后续的数量表不得与技术要求文档或更早记录的语义缺口悄然矛盾。
模块根目录只保留一套当前有效的四份文档。不要在其旁留下 *-历史详细版.md 或第二份 history/**/<current-name>.md。将有用的旧包分组、设计背景和决策历史合并到对应当前文档中,并明确标记为“历史设计附录”。生成的当前事实区域必须保持在文档最前面,重新生成时须保留附录。旧数量、路径、状态、测试和完成标记均不得覆盖当前事实。
将脚手架的 --force 视为破坏性操作,仅用于可丢弃且未经修改的 DRAFT;绝不可用它来合并或刷新已有内容的当前文档。应直接在当前文档中合并历史详情,同时保留其生成的事实区域和现有附录。
4. 如实分类每个对象
一致使用以下对象状态。将验证级别(V0–V7)分开处理;不要虚构一个更友好的状态,也不要将测试结果直接转换为对象状态。
| State | Meaning |
|---|---|
MISSING | 预期的 Rust 对象文件不存在 |
MISPLACED | 存在同名文件或类型,但不在确定性的预期路径下 |
STUB | 存在结构或占位内容,但缺少实际行为 |
PARTIAL | 存在实际行为,但方法、回调、错误、顺序、生命周期或集成语义不完整 |
UNVERIFIED | 文件或逻辑存在,但源代码注释、对象边界或语义测试证据不足 |
IMPLEMENTED | 预期路径、单对象边界、完整的实际逻辑、中文源代码语义和当前语义测试均已具备 |
DEPENDENCY_REUSED | 固定版本的依赖提供了完全相同的能力;已记录 crate/版本或提交、上游符号、适配器和本地集成测试 |
PLATFORM_NA | 该能力确实仅适用于 JVM/字节码/类加载器/平台,并且有明确证据说明为何不适用 Rust 对象 |
RUST_EXTENSION | 有意提供的 Rust 专属能力,不计入 Java 同等实现的分母 |
只有 IMPLEMENTED、DEPENDENCY_REUSED 和 PLATFORM_NA 才算处理了源对象。MISSING、MISPLACED、STUB、PARTIAL 和 UNVERIFIED 均为未完成状态。RUST_EXTENSION 永不计入 Java 分母。
只有在用户明确批准时,才允许使用计划中的占位内容。在路线图中记录阻塞因素,但让每个受影响对象保持其实际的 MISSING 或 STUB 状态。阻塞因素是元数据,不是类似完成状态的对象状态。
绝不能仅因为对象名称出现在清单、门面、lib.rs、mod.rs、重新导出、生成的注册表或兼容性模块中,就将状态从 MISSING 提升。绝不能仅因为 cargo test 全部通过,就将状态从 UNVERIFIED 提升。
5. 根据契约决定组件替换方案
不要直接映射框架名称。对于每个外部 Java 组件或框架子系统:
Java 源模块仍是对象名称、包结构和公共契约的权威依据。Rust 依赖项只是复用实现的边界。不要围绕依赖项的文件树重新组织迁移,也不要仅为提高对等性计数而将依赖项自有实现复制到本地文件中。例如,对于类似 AOP 的工作,Spring 定义 Advice/Interceptor/Advisor 对象清单,而 aspect crate 可以通过 DEPENDENCY_REUSED 满足特定运行时符号。
- 提取行为契约:API 形态、网络传输/存储格式、顺序、故障分类、生命周期、事务、并发、取消、背压、安全性、可观测性和部署假设。
- 选择替换形态:标准库、直接使用 crate、封装 crate、trait 加适配器、显式注册表/SPI、编译时宏/代码生成、由应用宿主负责,或已证实的
PLATFORM_NA。 - 将常见映射表和候选目录作为发现的起点,而不是自动批准依据。
- 如果没有经过验证的映射符合要求,则生成多个英文能力/协议/约束查询,在 crates.io 和配套的权威来源中搜索,并从 std、直接使用 crate、封装、trait/适配器、代码生成、宿主负责和排除等形态中筛选出 5 到 10 个候选项。
- 如有可用的
rust-crate-discovery,将 crates.io 元数据收集和生态健康度比较交由它处理。在此处应用迁移专用的契约和兼容性门槛;其数值健康评分不能决定替换方案。 - 在评分前,淘汰不满足所需契约、许可证、MSRV/目标平台、运行时/阻塞行为、协议、安全性、维护/所有权或依赖图约束的候选项。
- 根据语义契合度、维护情况、采用情况、文档/测试、项目兼容性、安全性/供应链、成熟度、成本和退出策略,对可行候选项进行比较。将下载量、反向依赖数、星标数、最近发布时间和提交记录视为背景信号,而非证明。
- 在确定架构前,先针对排名靠前的候选项,对风险最高的语义路径进行原型验证。
- 记录搜索查询和日期、所有权、版本/功能、各维度的证据/置信度、被拒绝的替代方案、退出方案和回滚计划。
- 只有在记录了确切的上游符号、固定版本的依赖证据、适配器边界和本地集成测试后,才将对象标记为
DEPENDENCY_REUSED。“生态中有这个”或“语义相似”仍属于UNVERIFIED。
对于多个目标框架,应定义框架无关的契约和轻量适配器,然后针对每个适配器运行同一套一致性测试。运行时 traits/类型应与轻量过程宏和生成的代码分开。
在选择或批准第三方替换方案前,请阅读 组件替换决策 SOP、crate 替换方案的发现与评估 和 组件候选目录。目录仅用于发现候选项,不代表批准清单;在决策时,应重新核实发布情况、维护情况、许可证、MSRV、目标平台、安全公告、unsafe/构建脚本影响范围以及所需契约。
6. 在一次语义实现过程中完成已声明的批次
修改代码前,先阅读 目录结构与迁移规则、 目录路径对齐模式与错误目录 和 语义映射。然后执行整个已冻结批次,不要在对象级验收时暂停:
- 一次性建立目标模块树、共享错误、trait、注册表、适配器、序列化规则、并发模型和依赖边界。
- 按依赖顺序实现每个映射的 Java 对象和操作。每个 Java 对象恰好保留一个主
.rs文件,并在对应对象文件或显式协作者文件中实现实际逻辑。 - 在整个批次中,将 JavaDoc 语义复制并翻译为中文 Rust 文档注释。逐一迁移每个现有的对象注释、构造函数/方法注释、泛型和取值
@param、@return、@throws、@since、@deprecated、相关的@see以及语义性行内注释,不得遗漏。保留针对具体参数的约定。将 Java 到 Rust 的名称、签名和异常映射保留在四份迁移文档中;生成的 Rust 文档应采用 Rust 原生形式。 - 将所有映射的重载变体、示例、fixture、源测试对应项、Rust 特定义务和基于风险的测试作为批次产物实现,但暂不执行验证。完整保留 100% 的源测试输入、断言、错误预期、状态、副作用和清理操作。复制源测试文件/数据/资源,不得编辑;任何 Rust 特定派生内容都应放入单独文件。
- 维护一份待处理问题清单。继续处理本地不确定事项;仅当阻碍会改变已冻结的公共约定、架构、依赖策略或授权范围时才暂停。
- 所有非豁免清单行均已完成实际实现后,冻结 Rust 批次。此后才可批量更新四份文档并进入审计阶段。
在此过程中,不要运行 cargo check、测试、Clippy、覆盖率检查、差异比较、逐对象 CodeGraph 重新查询或逐对象完成情况审查。不得仅因某个对象的文件已编辑就报告该对象已验收。允许提交恢复性代码,但这些提交不属于验证关卡。
迁移文档前,请先阅读 注释迁移约定与示例。将缺失的源注释视为迁移缺漏,而非可选的清理工作。
7. 保留命名和重载意图
- Rust 目录、文件、方法和参数使用
snake_case。 - Rust 类型使用
PascalCase。 - 将
loadOrCreateAgentState(slotKey)映射为load_or_create_agent_state(slot_key)。 - 移除组织名和声明的源模块包根目录,然后保留最终剩下的两个包段。若只剩一个,则保留该段;根包对象放在 crate 根目录。例如:
factory/xml/support/Foo.java→xml/support/foo.rs;propertyeditors/PatternEditor.java→propertyeditors/pattern_editor.rs。 lib.rs和mod.rs仅用于声明和重新导出。- 每个 Rust 文件保留一个 Java 类/接口/枚举/记录;与主类型紧密关联的内部构建器可以与其放在一起。
- 将 500 行物理代码视为内聚性审查阈值,将 800 行视为自编写文件的阻止阈值。按职责拆分,而非按行数范围拆分;子文件不得引入其他已迁移对象。
- 启用
clippy::too_many_lines,将其默认的 100 行阈值作为函数/方法审查信号;当长例程组合了不同职责时,应进行重构。 - 遵循 Rust 惯用的测试组织方式:将针对性单元测试放在
#[cfg(test)]模块中;将公共边界、跨模块、差分、宿主和整个项目的测试放在tests/或测试/testkit 包中。 - 在对象文档和命名一致性文档中记录每项有意的重命名。
Rust 不支持方法重载。只有当签名代表同一种语义操作时,才保留一个规范的 snake_case 名称。为其他变体添加稳定的语义后缀,例如 _with_charset、_into 或 _from_reader;记录每个 Rust 函数对应的确切 Java 签名。绝不能合并默认值、验证、副作用或错误行为不同的重载。
对每个已迁移的公共 Rust 接口,都应用本地的 rust-api-design 约定。不要机械地翻译 JavaBean 访问器:优先使用 name() 而非 get_name()(真正的查找操作除外);使用 set_name(value) 进行受控变更;仅在不会绕过不变量时使用 name_mut();使用 into_name()/into_inner() 转移所有权;使用语义明确的布尔谓词和可链式调用的构建器。按照 Rust 的语义使用 as_/to_/into_、From/TryFrom/AsRef 和 IntoIterator;不要使用 Deref 模拟 Java 继承。只有在不变量和 API 演进允许时,才直接公开字段。保留验证、可见性、副作用、异常、同步和惰性计算行为。
当脚本、表达式引擎、序列化器、反射门面或其他兼容性接口公开 Java 属性语义时,应保持 Rust API 惯用,并在显式注册表或成员解析器中实现旧有的字段/getter/setter 行为。将此关系记录为映射形式 ADAPTED;它与完成状态正交,仍需记录 IMPLEMENTED、UNVERIFIED 或其他符合事实的状态。
迁移 getter、setter、构建器或脚本可见属性之前,请阅读 Rust API and JavaBean property adaptation。
8. 翻译机制,而非照搬框架
将此表作为通用起点,然后核实确切契约和当前 crate 证据:
| Java 职责 | Rust 起点 |
|---|---|
| Jackson JSON 注解/模块 | serde、serde_json、项目自有的自定义序列化器 |
| Jackson XML / JAXB 风格的 XML | quick-xml,以及显式的命名空间、属性、混合内容和顺序逻辑 |
null、受检异常 | Option<T>;类型化的 thiserror 枚举和 Result |
| SLF4J/Logback/MDC | tracing、tracing-subscriber、显式的字段/上下文传递和脱敏 |
synchronized / ConcurrentHashMap | 优先考虑所有权;然后根据访问模式,使用标准库的 Mutex/RwLock 或 DashMap |
CompletableFuture、定时执行器 | 异步 Future、受监督的 Tokio 任务、取消令牌、定时器/间隔器;只有在需要更丰富的契约时才选择调度器 crate |
Reactor Mono<T> / Flux<T> | async fn -> Result<T, E>;有界的 Stream<Item = Result<T, E>> |
| OkHttp / Apache HttpClient | 用于高级客户端的 reqwest;用于协议级控制的 Hyper;验证 TLS、代理、连接池、重定向、重试和流式处理语义 |
| Spring MVC/WebFlux / JAX-RS | 与框架无关的核心,加上经批准的 Axum、Actix Web、Poem 或其他轻量宿主适配器 |
| JDBC/JPA/MyBatis | 根据查询、映射、事务、迁移和运行时契约,选择 SQLx、Diesel、SeaORM、RBatis 或其他经过验证的数据层 |
| Caffeine/Guava 缓存 | Moka 或项目自有缓存;验证逐出、TTL/TTI、加载、失效和并发行为 |
| Jedis/Lettuce | redis;验证集群/sentinel、重连、管道/事务、TLS 和异步行为 |
| Kafka/RabbitMQ/Pulsar/NATS/MQTT | 特定协议的客户端,例如 rdkafka、Lapin、pulsar、async-nats 或 rumqttc;要求具备真实 broker 语义和恢复测试 |
| Protobuf / gRPC | Protobuf;用于 gRPC 的 Tonic 和 Protobuf |
| Bean Validation | validator 或项目自有验证,并与框架提取器分开 |
java.time、UUID/ULID、BigDecimal、正则表达式 | time/chrono、uuid/ulid、rust_decimal/bigdecimal、regex;在优先选择 crate 之前,先确定表示形式和兼容性 |
.properties、YAML、TOML、配置绑定 | java-properties、serde_yaml_ng、toml 或经过验证的配置 crate,加上项目自有的优先级/配置档规则 |
| Apache Commons/Hutool 通用工具 | 优先使用标准库,然后使用 url、bytes、regex、base64 或 hex 等专用 crate;不要按名称寻找一个包罗万象的 crate |
| Micrometer/OpenTelemetry/Prometheus | metrics、OpenTelemetry 生态、Prometheus 导出器和 tracing 集成;保留名称、标签、基数、上下文和关闭行为 |
| JavaMail | lettre;验证 MIME、附件、TLS/身份验证、重试和投递报告 |
| JWT/密码/通用加密 | jsonwebtoken、argon2 和专用 RustCrypto crate;根据安全契约选择算法/格式,绝不能只考虑便利性 |
| Groovy/Nashorn/嵌入式脚本 | 根据语言、沙箱、资源限制、线程和打包要求,选择 rhai、boa_engine、mlua、PyO3 或 Wasmtime |
| Apache POI/文档格式 | 特定格式的 crate,例如 rust_xlsxwriter、calamine、docx-rs、printpdf 或 lopdf;使用实际的 Office/PDF 样例验证不支持的功能 |
| ServiceLoader/SPI | 优先使用显式注册表;仅在需要链接时注册时使用 inventory |
| Spring IoC/AOP/运行时注解 | 构造函数/构建器、trait、中间件、注册表、包装器;仅在需要编译时行为时使用宏 |
| FreeMarker / Velocity / 编译时视图 | Tera / Handlebars;编译时模板使用 Askama;Rust 原生标记使用 maud |
| Lombok 数据样板代码 | 使用标准派生宏,以及保留不变量的 API/构建器;仅根据生成的 API 契约评估 lombok-macros |
| JUnit/Testcontainers | Rust 单元/集成测试;使用 testcontainers 管理可丢弃的真实依赖 |
| JNI/手动 Swift/Kotlin/Python 绑定 | 当 UniFFI 支持的类型/错误/异步模型满足需求时使用;交付和打包仍需单独处理 |
| 优先组合成熟的 Rust crate,而不是重新实现 Java 全家桶,但在兼容性有要求时,保留源项目可观察到的外观。 |
9. 在稳定的宏边界后提取注解行为
不要将过程宏入口放在普通运行时 crate 中。请使用:
project-core # runtime traits, types, errors, and generated-code contract
project-macros # thin proc-macro entry points and syntax parsing
project-web-* # framework adapters that may re-export approved macros
仅当公共接口只有派生宏时,才使用 -derive;对于属性宏、类函数宏或混合宏,使用 -macros,除非现有 crate 系列已约定使用其他命名。生成的代码应依赖公共运行时 API,而不是过程宏内部实现。测试展开成功、编译失败、泛型、可见性、依赖重命名,以及每个框架的重新导出。
Java 运行时注解不会自动变成 Rust 宏。如果行为由运行时状态和动态分发决定,请使用中间件、trait、注册表或显式构建器。
10. 一次性审计,然后验证完整批次
实现冻结后,对整个已声明批次执行适用的验证流程:
- 对所有对象、文件、精确签名、参数、重载、调用路径、动态边界、示例、测试、文档和占位符,执行一次整合式 CodeGraph/静态对等性审计。将完整的 Java 注释清单与 Rust 对象、方法、参数、返回值、错误、元数据和行内注释进行比较。一次性协调全部四份文档。
- 将 Rust 格式检查、检查、单元测试、文档测试、集成测试、Clippy、特性、目标平台和平台门禁作为一套统一的工程验证套件运行。
- 运行所有已移植/镜像的 Java 契约测试,并明确标注为非差分证据。
- 运行完整的固定版本 Java 测试套件和完整的 Rust 无损移植测试套件,然后对每个具体源用例运行完整的 Java 黄金测试导出器或实时 Java/Rust 差分测试套件。要求两个测试套件都通过,且每个用例均报告
MATCH;不允许有不匹配、测试框架故障或未运行用例。请从专用的<project>-test包中执行;本地生产 crate 测试仅作为子系统证据。 - 针对两种实现,重放全部真实用户脚本和示例。
- 在适用时,运行并发验收,检查顺序、取消、背压、竞态、关闭以及 Loom/模型属性。
- 运行负载/稳定性测试,检查吞吐量、延迟百分位数、内存、句柄/任务、重连和长时间运行情况。
- 运行安全属性测试、畸形输入测试套件、
cargo-fuzz、不安全代码审查、依赖项安全公告检查和机密信息脱敏检查。 - 使用数据库、网络、文件、框架和部署拓扑,进行真实业务宿主集成。
- 执行灰度发布和回滚演练,并记录恢复时间和状态兼容性。
如果某个门禁失败,请按共用子系统或根因归类问题,修复整个批次,然后重新运行受影响的整合式门禁及其后续失效门禁。切勿退回到逐个对象迁移、比较和测试。
请阅读验证与验收,了解如何设计证据;并使用 rust-java-migration-testing 了解三账本测试 SOP。在修复无法编译或警告过多的工作区之前,请阅读编译偏移与迁移清理:依赖项/版本偏移、MSRV、crate 根重新导出链中断、跨 crate 类型重复、Java 镜像命名/脚手架规范,以及零警告检查工作流(默认配置 + --all-features、分层报告错误的 --keep-going、按 crate 归因、清理后运行测试)。
11. 在不夸大覆盖范围的情况下报告完成情况
分别报告结构、实现、行为、测试、集成和生产就绪情况。对于行为,区分镜像契约、黄金差分、实时差分和获批的等效判定依据;对于测试,区分无损迁移的源测试和 Rust 原生新增测试。
列出确切的命令、SHA、测试数量、失败情况、例外情况和未经验证的边界。绝不能仅仅因为代码可以编译或一致性清单达到 100%,就称迁移已完成。
红线
- 不要在
lib.rs、mod.rs或compat.rs中定义许多迁移对象。 - 不要将每个对象都委托给同一个
compat.rs实现。 - 不要用空函数体、
todo!()或unimplemented!()冒充已完成迁移。 - 不要为了让数量对得上而删除或简化已迁移的可用行为。
- 不要在生产迁移代码中使用通配符导入。
- 不要悄悄将多个 Java 对象合并到一个 Rust 文件中。
- 不要让手写的
.rs文件超过 800 个物理行;检查每个超过 500 行的文件,若内聚性较差,就将其拆分。 - 不要为了满足大小门槛而机械压缩代码、删除有用的注释,或随意按行数范围拆分文件。
- 不要将集成、差分、宿主、负载或全项目验收测试套件嵌入生产模块;内联的
#[cfg(test)]单元测试仍可用于测试聚焦于模块私有行为的场景。 - 不要用一个有损的便捷函数取代重载行为。
- 如果符合 Rust 惯用写法的方法加上显式兼容适配器即可保留约定,就不要仅仅为了模仿 JavaBean 的命名而创建
get_*方法。 - 如果脚本或动态成员访问仍需要 Java 字段、getter、setter 解析,就不要认为惯用的 Rust getter/setter 已经足够。
- 不要把声明依赖、成功编译或独立 POC 称作经过验证的组件替换。
- 不要以替换依赖项的包或文件布局作为目标对象清单;源 Java 对象和确定性路径规则仍是权威依据。
- 如果没有固定的 crate/commit、准确的源符号、适配器证据和本地集成测试,就不要将语义相似的依赖项标记为
DEPENDENCY_REUSED。 - 不要将仅仅难以处理或缺失的工作标记为
PLATFORM_NA;必须提供 JVM/字节码/类加载器/平台特定的证据。 - 没有当前的硬性筛选和契约证据时,不要仅凭研究清单或本地约定文档中的内容,就将组件提升为“已选定”。
- 除非 Java 和 Rust 两种实现都参与测试,或有 Java 生成的黄金产物参与测试,否则不要将从 Java 测试复制来的 Rust 测试称为差分测试。
- 不要仅凭处置结果声明源测试已达到对等。每个源用例都需要无损的目标,并且黄金结果/实时结果为
MATCH;MISSING、BLOCKED和NOT_APPLICABLE都会阻止完成。 - 不要就地修改复制的源夹具、脚本、语料库、黄金文件或测试数据。验证源和目标的 SHA-256,并将生成的派生文件分开保存。
- 不要把各套件分别通过或测试总数相同视为对等;应逐个比较输出、错误、状态、副作用和清理情况。
- 不要用生产代码/绑定 crate 的本地测试替代未发布的
<project>-test全项目验收包。 - 除非有 Rust 发布、依赖、目标平台、宏/FFI 或生命周期方面的理由,否则不要将 Maven/Gradle 模块一对一复制成 Cargo 包。
- 不要强制所有工作区都采用
crates/布局或根目录扁平布局;应根据产品规模、模块族、仓库噪声和兼容性记录拓扑结构。 - 不要仅凭文件数量、解析器接受、通用的
is_ok()/is_err(),或“每个对象至少一个测试”就将某一行标记为已通过行为验证。 - 不要让四份迁移文档采用不同的基准或互相矛盾的完成状态。
- 不要同时保留当前文档和
-历史详细版/嵌套副本;应将有用的历史内容合并到生成事实区域之后。 - 不要替换生成的当前事实区域,也不要让重新生成操作丢弃已合并的附录。
- 如果只运行了 mock、编译或静态检查,就不要声称进行了实际测试。
- 提取模式时不要编辑参考源仓库。
- 不要针对每个对象、文件或方法交替进行迁移、比较和测试。
- 实施期间不要运行对象范围的验收测试;应先完成冻结批次,再进行集中审计和统一验证。
- 不要将恢复提交或本地编辑里程碑转化为完成检查点。
- 不要遗漏现有 Java 对象、构造函数、方法、参数、返回值、异常、生命周期、线程安全性、弃用信息或语义性内联注释。
- 不要用通用文字替换源文档,也不要仅凭
cargo doc就声称注释已对等。 - 不要在参数、返回值、错误变体、字段或内联注释中写
对应 Java。可选的对应关系提示仅限于 Rust 类型和构造函数/方法文档;详细对应关系应保留在四份文档中。 - 不要为了消除
non_camel_case_types/dead_code警告而重命名 Java 镜像 SCREAMING_SNAKE 枚举变体,或删除 Java 镜像脚手架类型;应使用#[allow(...)]并添加注释,保留完整的 Java 清单。 - 不要仅凭默认 features 门槛就宣称工作区干净;
--all-features也必须达到零警告。不要为了匹配较旧的本地 rustc 而悄悄降低rust-version,应通过rustup run <ver> cargo ...运行固定工具链。 - 清理依赖 crate 时不要编辑路径依赖项;应先根据
-->路径将每条警告归属到对应的 crate。 - 不要试图修复一次
--keep-going输出中的“所有错误”;错误会分层出现——先修复第一层,再重新运行并迭代。
完成标准
- 每个源模块的四份现行文档共享基线、契约和 Rust SHA;不存在重复项。
- 路线图记录了有依据的源模块到 crate 的边界及由项目驱动的拓扑;实际清单和成员路径与之相符。
- 每个对象都有确定性的末尾两段路径;在物理位置对齐之前,
MISPLACED始终视为未完成。 - 每个 Java 对象、方法、重载和参数都有处置结果。
- 每个源测试/用例都有无损的 Rust 实现,每项源资源都有逐字节一致的校验副本。
<project>-test是位于选定路径的工作区成员,设置了publish = false,并负责完整的源测试套件/差异测试命令及产物。- 完整的 Java/Rust 测试套件均通过,逐用例差异测试结果 100% 为
MATCH,且不存在测试框架失败或未运行的用例。 - 每项依赖复用、平台排除、阻塞项、例外和 Rust 扩展都有精确证据,并如实处理分母。
- 每个编写的
.rs文件最多 800 个物理行;超过 500 行的文件和超过 Clippy 100 行提示阈值的函数均已记录内聚性审查,且任何拆分都保留 Java 对象边界。 - 仅当单元测试用于测试聚焦的模块行为时才与代码放在一起;集成、差异、宿主、负载和整个项目的测试套件均放在
tests/或不发布的测试包中。 - 生产用 Rust 文件符合布局、文档、导入和无存根规则。
- 每个源文档记录的对象、成员、参数、返回值、异常、元数据标签和语义内联注释,都有可追溯的 Rust 对应项。
- 在运行任何验收门禁之前,已实现完整的既定批次。
- 一次整合的实现后奇偶一致性审计覆盖完整的冻结分母;未使用逐对象验证循环。
- 高价值调用链都有源代码链接的语义映射。
- 适用的差异测试、回放、并发、负载、模糊测试、宿主和回滚门禁均有证据或明确列出的未解决问题。
- 最终报告分别说明结构、实现、行为、集成和生产就绪情况。