1. 简介

本文将介绍 Manifold JSON——一个基于 JSON Schema 的 JSON 文档解析工具。我们将探讨它的功能、应用场景以及使用方法。

Manifold 是一套编译器插件集合,为 Java 应用提供多种高效特性。本文重点讲解如何利用它根据 JSON Schema 文件解析和构建 JSON 文档。

2. 安装

使用 Manifold 前必须确保编译器已正确配置。核心集成是作为 Java 编译器插件,需在 Maven 或 Gradle 项目中配置。此外,Manifold 还提供 IDE 插件提升开发体验。

2.1. Maven 编译器插件

在 Maven 中集成 Manifold 需同时添加依赖和编译器插件,两者版本必须一致(当前最新版为 2024.1.20)。

添加依赖与普通 Maven 依赖无异:

<dependency>
    <groupId>systems.manifold</groupId>
    <artifactId>manifold-json-rt</artifactId>
    <version>2024.1.20</version>
</dependency>

编译器插件配置需修改 maven-compiler-plugin

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.8.0</version>
    <configuration>
        <compilerArgs>
            <!-- 配置 manifold 插件 -->
            <arg>-Xplugin:Manifold</arg>
        </compilerArgs>
        <!-- 添加注解处理器路径 -->
        <annotationProcessorPaths>
            <path>
                <groupId>systems.manifold</groupId>
                <artifactId>manifold-json</artifactId>
                <version>2024.1.20</version>
            </path>
        </annotationProcessorPaths>
    </configuration>
</plugin>

这里做了两件事:

  1. 添加 -Xplugin:Manifold 编译参数
  2. 配置 Manifold JSON 注解处理器(负责从 Schema 生成代码)

2.2. Gradle 编译器插件

Gradle 集成方式类似但配置更简洁

dependencies {
    implementation 'systems.manifold:manifold-json-rt:2024.1.20'
    annotationProcessor 'systems.manifold:manifold-json:2024.1.20'
    testAnnotationProcessor 'systems.manifold:manifold-json:2024.1.20'
}

仍需手动添加编译参数:

tasks.withType(JavaCompile) {
    options.compilerArgs += ['-Xplugin:Manifold']
}

至此环境准备就绪。

2.3. IDE 插件

除构建工具插件外,Manifold 还提供 IntelliJ/Android Studio 插件IDE Plugins 1

安装后,IDE 内编译即可触发 Manifold 插件,无需依赖构建工具。

3. 使用 JSON Schema 定义类

配置完成后,在 src/main/resources(或 src/test/resources)目录创建 JSON Schema 文件即可定义类。文件路径将直接映射为完整类名。

例如创建 com.baeldung.manifold.SimpleUser 类: 路径:src/main/resources/com/baeldung/manifold/SimpleUser.json

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "http://baeldung.com/manifold/SimpleUser.json",
  "type": "object",
  "properties": {
    "username": {
      "type": "string",
      "maxLength": 100
    },
    "name": {
      "type": "string",
      "maxLength": 80
    },
    "email": {
      "type": "string",
      "format": "email",
      "maxLength": 260
    }
  },
  "required": [
    "username",
    "name"
  ]
}

这定义了一个包含三个 String 字段的类:usernamenameemail

⚠️ 重要:Manifold 采用惰性生成机制,仅当代码引用 Schema 文件时才会生成类。哪怕简单变量定义也算有效引用。

4. 实例化 Manifold 类

生成的类并非标准 Java 类,而是接口。因此不能直接使用 new 创建实例。

生成代码提供了静态 create() 方法作为构造器,需按 required 数组顺序传入必填字段:

public static SimpleUser create(String username, String name);

其他字段可通过 setter 填充:

SimpleUser user = SimpleUser.create("testuser", "Test User");
user.setEmail("[email protected]");

还支持 Builder 模式,通过 build() 方法链式调用:

SimpleUser user = SimpleUser.builder("testuser", "Test User")
  .withEmail("[email protected]")
  .build();

✅ 对于只读可选字段,Builder 模式是唯一赋值途径——实例创建后无法修改此类字段。

5. 解析 JSON

生成类提供 load() 方法从多种数据源解析 JSON

解析方式

  • fromJson():解析 JSON 字符串
  • fromJsonFile():从文件读取
  • fromJsonReader():从 Reader 读取
  • fromJsonUrl():从 URL 读取(底层使用 java.net.URL.openStream()

字符串解析示例

SimpleUser user = SimpleUser.load().fromJson("""
    {
        "username": "testuser",
        "name": "Test User",
        "email": "[email protected]"
    }
    """);

文件流解析示例

InputStream is = getClass().getResourceAsStream("/com/baeldung/manifold/simpleUserData.json");
InputStreamReader reader = new InputStreamReader(is);
SimpleUser user = SimpleUser.load().fromJsonReader(reader);

❌ 解析失败会抛出 RuntimeException,内嵌 manifold.rt.api.ScriptException 描述具体错误。

6. 生成 JSON

与解析对应,生成类提供 write() 方法将对象转为 JSON

生成方式

  • toJson():返回 JSON 字符串
  • 写入任何 Appendable 实现(如 WriterStringBuilder

字符串生成示例

SimpleUser user = SimpleUser.builder("testuser", "Test User")
  .withEmail("[email protected]")
  .build();
String json = user.write().toJson();

文件写入示例

user.write().toJson(writer); // writer 可指向文件/网络等

✅ 支持写入内存缓冲区、文件或网络连接等任意目标。

7. 其他格式支持

虽然核心是 JSON,但 Manifold 也支持 CSV、XML 和 YAML

需添加对应依赖:

  • CSV:systems.manifold:manifold-csv-rt
  • XML:systems.manifold:manifold-xml-rt
  • YAML:systems.manifold:manifold-yaml-rt

多格式示例

SimpleUser user = SimpleUser.load().fromXmlReader(reader);
String yaml = user.write().toYaml();

8. JSON Schema 高级特性

8.1. 只读/只写字段

只读字段(readOnly: true)不生成 setter

"username": {
    "type": "string",
    "readOnly": true
},

只能在构造或解析时赋值,后续不可修改。

只写字段(writeOnly: true)不生成 getter

"mfaCode": {
    "type": "string",
    "writeOnly": true
},

可赋值但无法通过 Java 类读取(生成 JSON 时仍会输出)。

8.2. 格式化类型

Schema 中的 format 会影响生成的 Java 类型

  • date-timejava.time.LocalDateTime
  • emailString(带格式校验)

8.3. 动态属性

additionalProperties: true 允许任意扩展字段(默认开启):

user.put("note", "Schema 未定义的字段");

⚠️ 警告:无类型校验,可能覆盖 Schema 定义字段。

patternProperties 部分支持

"patternProperties": {
  "note[0-9]": {
    "type": "string"
  }
}

Manifold 会将其视为 additionalProperties: true

8.4. 嵌套类型

支持在 Schema 中定义嵌套对象

{
  "properties": {
    "email": {
      "type": "object",
      "properties": {
        "address": { "type": "string" },
        "verified": { "type": "boolean" }
      },
      "required": ["address", "verified"]
    }
  }
}

生成内部类,使用方式:

User user = User.builder()
  .withEmail(User.email.builder("[email protected]", false).build())
  .build();

8.5. 类型组合

支持 allOf/anyOf/oneOf 组合类型

allOf 示例(合并所有属性)

"allOf": [
  {"properties": {"username": {"type": "string"}}},
  {"properties": {"roles": {"type": "array", "items": {"type": "string"}}}}
]

生成类包含所有字段:

Composed.user.builder()
    .withUsername("testuser")
    .withRoles(List.of("admin"))
    .build()

anyOf/oneOf 示例(类型安全多选)

"anyOf": [
  {"$ref": "#/definitions/Dog"},
  {"$ref": "#/definitions/Cat"}
]

生成类型安全方法:

Composed composed = Composed.builder()
  .withAnimalAsCat(Composed.Cat.builder()
    .withColor("ginger")
    .build())
  .build();

assertEquals("ginger", composed.getAnimalAsCat().getColor());

9. 总结

本文全面介绍了 Manifold JSON 的核心功能。这个库还有更多高级特性等你探索,不妨亲自上手试试?


原始标题:Parse JSON with Manifold | Baeldung