用了json这么久我猜你一定不知道json schema是啥

大家好,这里是小奏 ,觉得文章不错可以关注公众号小奏技术

什么是 json schema

json schema 是一种用于描述 json 数据结构的语言,它可以用来定义 json 数据的类型、格式、约束等信息。

json schema 本身是一个也是json数据

主要用途

  • 数据校验
  • 数据结构定义
  • API文档生成
  • 代码生成

github地址

文档

java相关sdk选型

json schema推荐了各个语言相关sdk

这里我们主要看看java相关的sdk有哪些

简单对上面的一些进行调研分析

项目地址 start数量 项目活跃情况 备注
github.com/everit-org/... 861 基本不维护 这个是最早的json-schema的java实现,推荐使用json-sKema
github.com/erosb/json-... 49 活跃 与json-schema是同一个作者,不同的是这个是最新的
github.com/networknt/j... 848 活跃 jackson官方使用的是这个库,目前主流的json序列化库也是使用的这个库,所以推荐使用这个库

这里推荐是使用json-schema-validator

json-schema-validator也给了一份详细的对比文档

总体功能对比(越高越好)

整体可选功能(越高越好)

性能对比(越低越好)

更多对比参考文档 www.creekservice.org/json-schema...

json schema数据校验格式

这里我们主要探讨的是json schema如何对json数据如何进行数据校验

语法

中文文档其实说的已经很全面了,我们这里就主要对几种常用的对象类型的数据格式校验进行说明

必须包含某些属性

json 复制代码
{
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "email": { "type": "string" },
    "address": { "type": "string" },
    "telephone": { "type": "string" }
  },
  "required": ["name", "email"]
}

主要使用required关键字

这里代表json中必须包含nameemail属性

json 复制代码
// OK
{
  "name": "William Shakespeare",
  "email": "bill@stratford-upon-avon.co.uk"
}

// OK,提供额外的属性是可以的,即使是架构中没有定义的属性:
{
  "name": "William Shakespeare",
  "email": "bill@stratford-upon-avon.co.uk",
  "address": "Henley Street, Stratford-upon-Avon, Warwickshire, England",
  "authorship": "in question"
}

 // not OK,缺少必需的"email"属性会使 JSON 文档无效
{
  "name": "William Shakespeare",
  "address": "Henley Street, Stratford-upon-Avon, Warwickshire, England",
}

 // not OK,在 JSON 中,具有值的属性null不等同于不存在的属性。这失败,因为null不是"字符串"类型,而是"空"类型
{
  "name": "William Shakespeare",
  "address": "Henley Street, Stratford-upon-Avon, Warwickshire, England",
  "email": null
}

不能包含额外属性

json 复制代码
{
  "type": "object",
  "properties": {
    "number": { "type": "number" },
    "street_name": { "type": "string" },
    "street_type": { "enum": ["Street", "Avenue", "Boulevard"] }
  },
  "additionalProperties": false
}

主要是通过additionalProperties控制

json 复制代码
// OK
{ "number": 1600, "street_name": "Pennsylvania", "street_type": "Avenue" }

 // not OK,额外属性"direction"使对象无效
{ "number": 1600, "street_name": "Pennsylvania", "street_type": "Avenue", "direction": "NW" }

当然,也可以使用非布尔类型进行更灵活的限制 比如 所有额外属性必须是字符串

json 复制代码
{
  "type": "object",
  "properties": {
    "number": { "type": "number" },
    "street_name": { "type": "string" },
    "street_type": { "enum": ["Street", "Avenue", "Boulevard"] }
  },
  "additionalProperties": { "type": "string" }
}
json 复制代码
// OK
{ "number": 1600, "street_name": "Pennsylvania", "street_type": "Avenue" }

// OK,这是有效的,因为附加属性的值是一个字符串
{ "number": 1600, "street_name": "Pennsylvania", "street_type": "Avenue", "direction": "NW" }

 // not OK,这是无效的,因为附加属性的值不是字符串:
{ "number": 1600, "street_name": "Pennsylvania", "street_type": "Avenue", "office_number": 201 }

对所有属性进行正则校验

我们也可以通过正则对所有属性进行更灵活的正则匹配校验

json 复制代码
{
  "type": "object",
  "propertyNames": {
    "pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
  }
}
json 复制代码
// OK
{
  "_a_proper_token_001": "value"
}
 // not OK
{
  "001 invalid": "value"
}

属性数量限制

我们可以通过minPropertiesmaxProperties来限制属性的数量

json 复制代码
{
  "type": "object",
  "minProperties": 2,
  "maxProperties": 3
}
json 复制代码
{}  // not OK
{ "a": 0 }  // not OK
{ "a": 0, "b": 1 } // OK
{ "a": 0, "b": 1, "c": 2 } // OK
{ "a": 0, "b": 1, "c": 2, "d": 3 }  // not OK 

java sdk初体验

这里我们以json-sKemajson-schema-validator进行举例

  • jdk 17

json-sKema

  1. 引入依赖
xml 复制代码
        <dependency>
            <groupId>com.github.erosb</groupId>
            <artifactId>json-sKema</artifactId>
            <version>0.18.0</version>
        </dependency>

        <dependency>
        <groupId>org.jetbrains.kotlin</groupId>
        <artifactId>kotlin-stdlib</artifactId>
        <version>1.8.0</version>
        </dependency>
  1. 代码使用
java 复制代码
public class JsonsKemaTest {

    private static final Validator validator;

    static {
        JsonValue schemaJson = new JsonParser("""
            {
            	"$schema": "https://json-schema.org/draft/2020-12/schema",
            	"type": "object",
            	"properties": {
            		"age": {
            			"type": "number",
            			"minimum": 0
            		},
            		"name": {
            			"type": "string"
            		},
            		"email": {
            			"type": "string",
            			"format": "email"
            		}
            	}
            }
            """).parse();
        Schema schema = new SchemaLoader(schemaJson).load();
        validator = Validator.create(schema, new ValidatorConfig(FormatValidationPolicy.ALWAYS));
    }

    @Test
    public void testJsonSchemaFailure() {
        JsonValue instance = new JsonParser("""
            {
            	"age": -5,
            	"name": null,
            	"email": "invalid"
            }
            """).parse();
        ValidationFailure failure = validator.validate(instance);
        if (Objects.nonNull(failure)) {
            failure.getCauses().forEach(System.out::println);

        }

    }

    @Test
    public void testJsonSchemaSuccess() {
        JsonValue success = new JsonParser("""
            {
            	"age": 3,
            	"name": "xiaozou",
            	"email": "111423@qq.com"
            }
            """).parse();

        ValidationFailure validateSuccess = validator.validate(success);
        if (Objects.isNull(validateSuccess)) {
            System.out.println(" validate json success");
        }
    }

}

校验失败运行结果

json-sKema

  1. 引入依赖
xml 复制代码
        <dependency>
            <groupId>com.networknt</groupId>
            <artifactId>json-schema-validator</artifactId>
            <version>1.5.2</version>
        </dependency>
  1. 代码使用
java 复制代码
class JsonSchemaDemoTest {

    private static final JsonSchema jsonSchema;

    static {

        String schemaData = """
            {
            	"$schema": "https://json-schema.org/draft/2020-12/schema",
            	"type": "object",
            	"properties": {
            		"age": {
            			"type": "number",
            			"minimum": 0
            		},
            		"name": {
            			"type": "string"
            		},
            		"email": {
            			"type": "string",
            			"format": "email"
            		}
            	}
            }
            """;

        JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V202012,
            builder -> builder.jsonNodeReader(JsonNodeReader.builder().locationAware().build()));

        SchemaValidatorsConfig config = SchemaValidatorsConfig.builder().build();

        jsonSchema = factory.getSchema(schemaData, InputFormat.JSON, config);

    }

    @Test
    public void testValidationSuccess() {

        String input = """
            {
            	"age": 3,
            	"name": "xiaozou",
            	"email": "111423@qq.com"
            }
            """;
        Set<ValidationMessage> assertions = jsonSchema.validate(input, InputFormat.JSON, executionContext -> {
            // By default since Draft 2019-09 the format keyword only generates annotations and not assertions
            executionContext.getExecutionConfig().setFormatAssertionsEnabled(true);
        });

        System.out.println(assertions);

    }

    @Test
    public void testJsonSchemaFailure() {

        String input = """
            {
            	"age": -5,
            	"name": null,
            	"email": "invalid"
            }
            """;
        Set<ValidationMessage> assertions = jsonSchema.validate(input, InputFormat.JSON, executionContext -> {
            // By default since Draft 2019-09 the format keyword only generates annotations and not assertions
            executionContext.getExecutionConfig().setFormatAssertionsEnabled(true);
        });

        System.out.println(assertions);

    }
}    

校验失败运行结果

[/age: 最小值必须为 0, /name: 已找到 null,必须是 string, /email: 与 email 模式不匹配必须是有效的 RFC 5321 邮箱]

可以看到相比于json-sKemajson-schema-validator的校验结果使用起来更方便、简洁

总结

总的来说如果需要进行json数据校验,推荐使用json-schema-validator,它的校验结果更加简洁,使用起来更加方便

在官方的对比文档中也可以看出来json-schema-validator的功能更加全面,性能也更好,可扩展性也是非常强的

同时json-schema-validator也是目前主流的json序列化库使用的校验库

相关推荐
捂月25 分钟前
Spring Boot 深度解析:快速构建高效、现代化的 Web 应用程序
前端·spring boot·后端
瓜牛_gn1 小时前
依赖注入注解
java·后端·spring
Estar.Lee1 小时前
时间操作[取当前北京时间]免费API接口教程
android·网络·后端·网络协议·tcp/ip
喜欢猪猪1 小时前
Django:从入门到精通
后端·python·django
一个小坑货1 小时前
Cargo Rust 的包管理器
开发语言·后端·rust
bluebonnet271 小时前
【Rust练习】22.HashMap
开发语言·后端·rust
uhakadotcom2 小时前
如何实现一个基于CLI终端的AI 聊天机器人?
后端
Iced_Sheep2 小时前
干掉 if else 之策略模式
后端·设计模式
XINGTECODE3 小时前
海盗王集成网关和商城服务端功能golang版
开发语言·后端·golang
程序猿进阶3 小时前
堆外内存泄露排查经历
java·jvm·后端·面试·性能优化·oom·内存泄露