1. 概述

本教程将使用 Java JSON Schema Generator 库,在 Java 中创建 JSON Schema。我们将学习:

✅ 生成简单和递归的 JSON Schema
✅ 配置不同的 Schema 参数
✅ 使用 JacksonJakarta Validation 模块派生 Schema
✅ 通过 Maven 插件 在构建时生成 Schema

2. 环境准备

2.1 核心依赖

首先添加核心依赖 *jsonschema-generator*:

<dependency>
    <groupId>com.github.victools</groupId>
    <artifactId>jsonschema-generator</artifactId>
    <version>4.31.1</version>
</dependency>

该依赖包含 Schema 生成和配置的主要 API

2.2 扩展模块

接下来安装三个模块,用于从类注解生成 Schema 属性:

Jackson 模块

<dependency>
    <groupId>com.github.victools</groupId>
    <artifactId>jsonschema-module-jackson</artifactId>
    <version>4.31.1</version>
</dependency>

Jakarta Validation 模块

<dependency>
    <groupId>com.github.victools</groupId>
    <artifactId>jsonschema-module-jakarta-validation</artifactId>
    <version>4.31.1</version>
</dependency>

2.3 Maven 插件

最后添加构建插件:

<plugin>
    <groupId>com.github.victools</groupId>
    <artifactId>jsonschema-maven-plugin</artifactId>
    <version>4.31.1</version>
    <executions>
        <execution>
            <goals>
                <goal>generate</goal>
            </goals>
        </execution>
    </executions>
</plugin>

⚠️ 重要提示:自 4.7 版本起,强烈建议模块和插件使用与核心依赖相同的版本。

3. 基础用法

3.1 简单 Schema

定义一个 Article 类:

public class Article { 
    private UUID id;
    private String title;
    private String content;
    private Date createdAt;
    private Area area;
    // getters and setters omitted
}

生成 Schema:

SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(SchemaVersion.DRAFT_2020_12, OptionPreset.PLAIN_JSON);
SchemaGeneratorConfig config = configBuilder.with(Option.EXTRA_OPEN_API_FORMAT_VALUES)
  .without(Option.FLATTENED_ENUMS_FROM_TOSTRING)
  .build();

SchemaGenerator generator = new SchemaGenerator(config);
JsonNode jsonSchema = generator.generateSchema(Article.class);

关键配置说明:

  • DRAFT_2020_12:使用最新 JSON Schema 规范(默认为 DRAFT-7
  • PLAIN_JSON 预设:仅使用非静态类字段生成 Schema
  • EXTRA_OPEN_API_FORMAT_VALUES:为特殊类型添加格式信息(如 UUID/date-time)

生成的 Schema:

{
    "$schema":"https://json-schema.org/draft/2020-12/schema",
    "type":"object",
    "properties":{
        "area":{
            "type":"string",
            "enum":["JAVA","KOTLIN","SCALA","LINUX"]
        },
        "content":{"type":"string"},
        "createdAt":{
            "type":"string",
            "format":"date-time"
        },
        "id":{
            "type":"string",
            "format":"uuid"
        },
        "title":{"type":"string"}
    }
}

📌 Java 的 DateUUID 被转换为带 format 的字符串类型,枚举通过 name() 方法转换

3.2 递归 Schema

定义递归类结构:

public class Author {
    private UUID id;
    private String name;
    private String role;
    private List<AuthoredArticle> articles;
    // getters, setters omitted
}

public class AuthoredArticle {
    private Author author;
    // getters and setters omitted
}

生成的 Schema 会包含循环引用:

{
    "author":{
        "type":"object",
        "properties":{
            "articles":{
                "type":"array",
                "items":{"$ref":"#"}
            }
        }
    }
}

✅ 规范允许循环引用,但 $ref 不能指向另一个 $ref

4. 高级配置

4.1 字段级配置

自定义 Author 类的 Schema 字段:

configBuilder.forFields()
  .withRequiredCheck(field -> field.getAnnotationConsideringFieldAndGetter(Nullable.class) == null)
  .withArrayUniqueItemsResolver(scope -> scope.getType().getErasedType() == List.class ? true : null);

效果:

  • @Nullable 字段标记为 required
  • List 类型字段添加 uniqueItems: true

生成的 Schema:

{
    "type":"object",
    "properties":{
        "articles":{
            "uniqueItems":true,
            "type":"array",
            "items":{
                "type":"object",
                "properties":{...},
                "required":["area","author","content","createdAt","id","title"]
            },
            "default":[]
        }
    },
    "required":["articles","id","name","role"]
}

类型级默认值配置:

configBuilder.forTypesInGeneral()
  .withDefaultResolver(scope -> 
    scope.getType().getErasedType() == List.class ? Collections.EMPTY_LIST : null)
  .withDefaultResolver(scope -> 
    scope.getType().getErasedType() == Date.class ? Date.from(Instant.now()) : null);

📌 返回 null 表示不在 Schema 中设置该属性

4.2 高级配置

使用 AdvancedArticle 类演示:

public class AdvancedArticle {
    private UUID id;
    private String title;
    @AllowedTypes({Timestamp.class, String.class, Date.class})
    private Object createdAt;
    // other fields omitted
}

添加只读属性:

configBuilder.forFields()
  .withInstanceAttributeOverride((node, field, context) -> 
    node.put("readOnly", field.getDeclaredType().isInstanceOf(UUID.class)));

效果:

{
    "id":{
        "type":"string",
        "format":"uuid",
        "readOnly":true
    },
    "title":{
        "type":"string",
        "readOnly":false
    }
}

处理多类型字段:

configBuilder.forFields()
  .withTargetTypeOverridesResolver(field -> 
    Optional.ofNullable(field.getAnnotationConsideringFieldAndGetterIfSupported(AllowedTypes.class))
      .map(AllowedTypes::value)
      .map(Stream::of)
      .map(stream -> stream.map(subtype -> field.getContext().resolve(subtype)))
      .map(stream -> stream.collect(Collectors.toList()))
      .orElse(null));

生成的联合类型:

{
    "createdAt":{
        "anyOf":[
            {"type":"object","properties":{"nanos":{"type":"integer","format":"int32"}}},
            {"type":"string","format":"date-time"}
        ]
    }
}

💡 高级配置支持自定义类型定义和属性定义,满足复杂场景需求

5. 模块使用

5.1 Jackson 模块

处理 Person 类的 Jackson 注解:

class Person {
    @JsonProperty(access = JsonProperty.Access.READ_ONLY)
    UUID id;

    @JsonProperty(access = JsonProperty.Access.READ_WRITE, required = true)
    String name;

    @JsonIgnore
    String fullName;

    @JsonProperty(access = JsonProperty.Access.READ_ONLY)
    Date createdAt;
    // other fields omitted
}

配置模块:

JacksonModule module = new JacksonModule(RESPECT_JSONPROPERTY_REQUIRED);
SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(DRAFT_2020_12, PLAIN_JSON)
  .with(module)
  .with(EXTRA_OPEN_API_FORMAT_VALUES);

生成的 Schema:

{
    "type":"object",
    "properties":{
        "createdAt":{
            "type":"string",
            "format":"date-time",
            "readOnly":true
        },
        "id":{
            "type":"string",
            "format":"uuid",
            "readOnly":true
        }
    },
    "required":["address","name","surname"]
}

✅ 自动忽略 @JsonIgnore 字段,正确处理 requiredreadOnly

5.2 Jakarta Validation 模块

使用验证注解装饰 Person 类:

class Person {
    @NotNull UUID id;
    
    @NotNull @Email
    @Pattern(regexp = "\\b[A-Za-z0-9._%+-]+@baeldung\\.com\\b")
    String email;

    @Null String fullName;
    
    @Size(max = 10) 
    List<Person> friends;
    // other fields omitted
}

配置模块:

JakartaValidationModule module = new JakartaValidationModule(
    NOT_NULLABLE_FIELD_IS_REQUIRED, 
    INCLUDE_PATTERN_EXPRESSIONS
);

生成的 Schema:

{
    "type":"object",
    "properties":{
        "email":{
            "type":"string",
            "format":"email",
            "pattern":"\\b[A-Za-z0-9._%+-]+@baeldung\\.com\\b"
        },
        "friends":{
            "maxItems":10,
            "type":"array",
            "items":{"$ref":"#"}
        },
        "fullName":{
            "type":["string","null"]
        }
    },
    "required":["createdAt","email","id","name","surname"]
}

📌 @Email 自动添加 format 字段,@Size 转换为 maxItems

6. Maven 插件配置

完整插件配置示例:

<plugin>
    <groupId>com.github.victools</groupId>
    <artifactId>jsonschema-maven-plugin</artifactId>
    <version>4.31.1</version>
    <executions>
        <execution>
            <goals>
                <goal>generate</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <packageNames>
            <packageName>com.baeldung.jsonschemageneration.plugin</packageName>
        </packageNames>
        <classNames>
            <className>com.baeldung.jsonschemageneration.plugin.Person</className>
        </classNames>
        <schemaVersion>DRAFT_2020_12</schemaVersion>
        <schemaFilePath>src/main/resources/schemas</schemaFilePath>
        <schemaFileName>{1}/{0}.json</schemaFileName>
        <failIfNoClassesMatch>true</failIfNoClassesMatch>
        <options>
            <preset>PLAIN_JSON</preset>
            <enabled>
                <option>DEFINITIONS_FOR_ALL_OBJECTS</option>
                <option>FORBIDDEN_ADDITIONAL_PROPERTIES_BY_DEFAULT</option>
            </enabled>
            <disabled>SCHEMA_VERSION_INDICATOR</disabled>
        </options>
        <modules>
            <module>
                <name>Jackson</name>
                <options>
                    <option>RESPECT_JSONPROPERTY_REQUIRED</option>
                </options>
            </module>
            <module>
                <name>JakartaValidation</name>
                <options>
                    <option>NOT_NULLABLE_FIELD_IS_REQUIRED</option>
                    <option>INCLUDE_PATTERN_EXPRESSIONS</option>
                </options>
            </module>
        </modules>
    </configuration>
</plugin>

执行 mvn compile 后生成文件路径:

src/main/resources/schemas/com/baeldung/jsonschemageneration/plugin/Person.json

⚠️ 插件不支持自定义模块的选项配置

7. 总结

本文系统介绍了使用 Java JSON Schema Generator 的核心能力:

  1. 基础生成:支持简单/递归 Schema,自动处理 Java 类型转换
  2. 灵活配置:字段级、类型级、方法级精细控制
  3. 模块化扩展:Jackson/Jakarta Validation 注解自动转换
  4. 构建集成:通过 Maven 插件实现自动化生成

完整代码示例可在 GitHub 获取


原始标题:Programmatic Generation of JSON Schemas in Java | Baeldung