json2rs:从 JSON 生成 Struct 定义,无需魔法
Source: Dev.to
我写了一个小型 CLI 工具,可以把 JSON 文件转换为 Rust、Python、TypeScript、Kotlin 和 Java 的结构体(类)定义。
它叫做 json2rs。
问题
你手里有一个 JSON 文件——可能是 API 响应,也可能是配置模式——需要为它编写结构体/类定义。手动编写既繁琐又容易出错。现有的生成器往往太“聪明”:它们会猜测、推断,悄悄生成几乎能编译的代码。
我想要点不一样的东西。
设计理念
快速且响亮地失败。 如果输入的 JSON 格式错误或存在歧义,导致会生成错误的输出,工具会立即停止并提示。没有静默失败,也没有生成的代码虽然能编译却与数据不符。
不做智能推断。 json2rs 不会尝试推断两个相似结构是否应该是同一种类型。它不猜测可选字段,也不进行合并。看到什么就生成什么。
输出像手写代码。 目标是让你感觉可以自己手写出这些代码。没有你未请求的额外派生(derive),没有包装类型,也没有框架假设。
最小化配置。 配置文件只有 17 行。如果你需要更多内容来描述想要的结果,说明工具本身可能做得太多了。
使用方法
json2rs input.json
json2rs input.json -c typescript
json2rs input.json -c python
输出会写入 stdout,可以随意管道到其他地方。
配置
Rust 输出的完整配置文件如下:
ext = "rs"
before_struct = "#[derive(Debug, serde::Serialize, serde::Deserialize)]\npub struct "
after_struct = "}\n\n"
before_struct_name = ""
after_struct_name = " {\n"
each_attr_format = " pub $NAME: $TYPE,\n"
number = "i64"
string = "String"
boolean = "bool"
array = "Vec"
object = "$T"
null = "serde_json::Value"
optional = "Option"
file_header = "use serde_json::Value;\n\n"
file_footer = ""
indent = " "
field_separator = ""
模板变量、前后缀分离以及按类型映射让你只需更换配置文件即可面向不同语言,而核心逻辑保持不变。这也是输出能像手写代码的原因:你定义了“手写”长什么样。
实现细节
核心约 400 行 Rust 代码,依赖少量库:
serde_json用于 JSON 解析clap用于 CLI 参数处理serde用于配置的序列化/反序列化anyhow用于错误处理toml用于解析配置文件lazy_static用于某些静态初始化
没有 async 运行时,也没有庞大的代码生成框架——依赖层保持有意的简洁。
在一次性能测试中,json2rs 处理了一个 14.5 MB、包含 1,065,218 行、嵌套深度为 11 层的 JSON 文件,仅用 148 ms 就生成了 Rust 结构体定义。这展示了它在大输入下的高效性。
类型推断本身设计为浅层:它遍历一次 JSON,将每个值映射到最字面化的类型并输出。需要启发式处理的边缘情况会直接报错。
它不是
- 不是 schema 生成器。
- 不是双向的。
- 它不会优雅地处理任意深度的多态嵌套类型——遇到这种情况会告诉你它做不到。
如果你想要一个会“努力”但有时会悄悄出错的工具,市面上还有其他选项。这个工具更倾向于少做尝试、并在出错时大声提示。
来源
github.com/BlophyNova/json2rs – 欢迎提交 issue 和 PR。