json-schema

json-schema

用于验证 JSON 数据是否符合JSON Schema规范Java库

json-schema 是一个 Java 库,用于验证 JSON 数据是否符合 JSON Schema 规范。支持 Draft 4、6 和 7 版本,使用 org.json API 处理数据。提供详细错误报告、验证监听、快速失败模式等功能。还可设置默认值、选择正则表达式实现和验证 readOnly/writeOnly 属性。适用于需要 JSON 数据验证的 Java 项目。

JSON Schema验证JavaDraftValidationExceptionGithub开源项目

JSON Schema 验证器 <a href="https://www.paypal.me/erosb88"><img style="float: right" width="70" height="35" src="https://yellow-cdn.veclightyear.com/835a84d5/eff18bbf-85d9-4754-8123-2c4d8f152345.jpg" title="通过捐赠支持这个项目"></a>

弃用通知

该库目前处于维护模式,已被 erosb/json-sKema 取代。

这个仓库不会有任何新功能。它为 JSON Schema 规范的 draft-04、draft-06 和 draft-07 版本提供了稳固的支持。

最新的 draft 2020-12 版本仅由 erosb/json-sKema 支持。

[![Apache 2.0 许可证][ASL 2.0 badge]][ASL 2.0] [![构建状态][Travis badge master]][Travis] [![覆盖率状态][Coveralls.io badge master]][Coveralls.io]

这个项目是 JSON Schema [Draft v4][draft-zyp-json-schema-04]、Draft v6Draft v7 规范的实现。 它使用 org.json API(由 Douglas Crockford 创建)来表示 JSON 数据。

何时使用这个库?

假设你已经知道什么是 JSON Schema,并且想在 Java 应用程序中使用它来验证 JSON 数据。 但是 - 你可能已经发现 - 还有[另一个 Java 实现][java-json-tools/json-schema-validator]的 JSON Schema 规范。以下是一些关于选择哪一个的建议:

  • 如果你使用 Jackson 在 Java 代码中处理 JSON,那么 [java-json-tools/json-schema-validator] 显然是更好的选择,因为它使用 Jackson
  • 如果你想使用 org.json API,那么这个库是更好的选择
  • 如果你需要 JSON Schema Draft 6 / 7 支持,那么你需要这个库
  • 如果你想使用其他任何东西来处理 JSON(比如 GSON 或 javax.json),那么你会遇到一些麻烦,因为 目前没有基于这些库的 schema 验证库。这意味着你将不得不解析 JSON 两次:一次用于 schema 验证器,一次用于你自己的处理。在这种情况下,这个库可能仍然 是更好的选择,因为它似乎比基于 Jackson 的 [java-json-tools][java-json-tools/json-schema-validator] 库快两倍

Maven 安装

在你的 pom.xml 中添加以下依赖:

<dependency> <groupId>com.github.erosb</groupId> <artifactId>everit-json-schema</artifactId> <version>1.14.4</version> </dependency>

关于旧版本的注意事项:版本 1.6.01.9.1 之间只能在 JitPack 上找到,坐标为 com.github.everit-org.json-schema:org.everit.json.schema。版本 1.0.0 ... 1.5.1 在 Maven Central 上可用,坐标为 org.everit.json:org.everit.json.schema

Java6/7 版本

有几次尝试使这个库在 Java 6/7 上工作。

@mindbender1 开发了 1.9.2 版本的 java6 移植版,可以通过 Maven Central 使用以下坐标访问:

<dependency> <groupId>com.github.erosb</groupId> <artifactId>everit-json-schema-jdk6</artifactId> <version>1.9.2</version> </dependency>

旧版本的向后移植:

  • 1.4.1 版本由 Doctusoft 向后移植,坐标为 com.doctusoft:json-schema-java7:1.4.1
  • 1.1.1 版本由 @rdruilhe 向后移植,可在 JitPack 上获得,坐标为 com.github.rdruilhe.json-schema:org.everit.json.schema:1.1.1

快速入门

import org.everit.json.schema.Schema; import org.everit.json.schema.loader.SchemaLoader; import org.json.JSONObject; import org.json.JSONTokener; // ... try (InputStream inputStream = getClass().getResourceAsStream("/path/to/your/schema.json")) { JSONObject rawSchema = new JSONObject(new JSONTokener(inputStream)); Schema schema = SchemaLoader.load(rawSchema); schema.validate(new JSONObject("{\"hello\" : \"world\"}")); // 如果这个对象无效,则抛出 ValidationException }

Draft 4、Draft 6 还是 Draft 7?

JSON Schema 目前有 4 个主要版本,Draft 3、Draft 4、Draft 6 和 Draft 7。这个库实现了其中的 3 个较新版本,你可以在这里这里快速了解它们之间的差异。 由于两个版本有许多差异 - 而且 draft 6 不向后兼容 draft 4 - 知道你将使用哪个版本是很好的。 指定要使用的JSON Schema版本的最佳方法是在文档根节点使用"$schema"键包含其元模式URL。这是一种常见的表示法,便于库确定应使用哪个版本。

快速参考:

  • 如果模式根节点有"$schema": "http://json-schema.org/draft-04/schema",则使用Draft 4
  • 如果模式根节点有"$schema": "http://json-schema.org/draft-06/schema",则使用Draft 6
  • 如果模式根节点有"$schema": "http://json-schema.org/draft-07/schema",则使用Draft 7
  • 如果没有找到以上任何一个,则默认使用Draft 4

如果你想明确指定元模式版本,可以通过如下方式配置加载器,将默认版本从Draft 4更改为Draft 6/7:

SchemaLoader loader = SchemaLoader.builder() .schemaJson(yourSchemaJSON) .draftV6Support() // 或 draftV7Support() .build(); Schema schema = loader.load().build();

调查失败原因

从1.1.0版本开始,验证器会收集所有模式违规(而不是在第一个违规处立即失败)。每个失败都用JSON指针表示,从文档根指向违规部分。如果检测到多个模式违规,则会在违规的最近公共父元素处抛出ValidationException,可以使用ValidationException#getCausingExceptions()方法获取每个单独的违规。

为了演示上述概念,让我们看一个例子。考虑以下模式:

{ "type" : "object", "properties" : { "rectangle" : {"$ref" : "#/definitions/Rectangle" } }, "definitions" : { "size" : { "type" : "number", "minimum" : 0 }, "Rectangle" : { "type" : "object", "properties" : { "a" : {"$ref" : "#/definitions/size"}, "b" : {"$ref" : "#/definitions/size"} } } } }

以下JSON文档对该模式只有一处违规(因为"a"不能为负):

{ "rectangle" : { "a" : -5, "b" : 5 } }

在这种情况下,抛出的ValidationException将指向#/rectangle/a,并且不包含子异常:

try { schema.validate(rectangleSingleFailure); } catch (ValidationException e) { // 打印 #/rectangle/a: -5.0 is not higher or equal to 0 System.out.println(e.getMessage()); }

现在,为了说明如何处理多个违规,让我们考虑以下JSON文档,其中"a"和"b"属性都违反了上述模式:

{ "rectangle" : { "a" : -5, "b" : "asd" } }

在这种情况下,抛出的ValidationException将指向#/rectangle,并且有2个子异常,分别指向#/rectangle/a#/rectangle/b:

try { schema.validate(rectangleMultipleFailures); } catch (ValidationException e) { System.out.println(e.getMessage()); e.getCausingExceptions().stream() .map(ValidationException::getMessage) .forEach(System.out::println); }

这将打印以下输出:

#/rectangle: 2 schema violations found
#/rectangle/a: -5.0 is not higher or equal to 0
#/rectangle/b: expected type: Number, found: String

失败的JSON报告

从1.4.0版本开始,可以将ValidationException实例打印为JSON格式的失败报告。ValidationException#toJSON()方法返回一个JSONObject实例,包含以下键:

  • "message": 对程序员友好的异常消息(验证失败的描述)
  • "keyword": 违反的JSON Schema关键字
  • "pointerToViolation": 一个JSON指针,表示从输入文档根到导致验证失败的片段的路径
  • "schemaLocation": 一个JSON指针,表示从模式JSON根到违反的关键字的路径
  • "causingExceptions": 一个(可能为空的)子异常数组。每个子异常都表示为一个JSON对象,结构与本列表中描述的相同。有关导致异常的更多信息,请参见上文。

请注意,完整的失败报告是一个层次树结构:可以使用#getCausingExceptions()获取一个原因的子原因。

ValidationListeners - 跟踪验证过程

ValidationListener可以用于解决实例JSON如何匹配(或不匹配)模式的歧义。你可以将ValidationListener实现附加到验证器,以接收有关中间成功/失败结果的事件通知。

示例:

import org.everit.json.schema.Validator; ... Validator validator = Validator.builder() .withListener(new YourValidationListenerImplementation()) .build(); validator.performValidation(schema, input);

当前支持的事件:

  • 解析"$ref"引用
  • "allOf" / "anyOf" / "oneOf"模式下的子模式匹配
  • "allOf" / "anyOf" / "oneOf"模式下的子模式匹配失败
  • "if"模式匹配
  • "if"模式匹配失败
  • "then"模式匹配
  • "then"模式匹配失败
  • "else"模式匹配
  • "else"模式匹配失败

有关更多详细信息,请参阅org.everit.json.schema.event.ValidationListener接口的javadoc。特定事件类还有适当的#toJSON()#toString()实现,因此你可以以易于解析的格式打印它们。

快速失败模式

默认情况下,验证错误报告处于收集模式(参见"调查失败原因"章节)。这对于获得详细的错误报告很方便,但在某些情况下,更适合在发现失败时停止验证,而不检查JSON文档的其余部分。要切换到这种快速失败验证模式:

  • 你必须显式为你的模式构建一个Validator实例,而不是调用Schema#validate(input)
  • 你必须调用ValidatorBuilderfailEarly()方法

示例:

import org.everit.json.schema.Validator; ... Validator validator = Validator.builder() .failEarly() .build(); validator.performValidation(schema, input);

注意:Validator 类是不可变的且线程安全的,因此你不需要为每次验证创建一个新的实例,只需配置一次即可。

宽松模式

在某些情况下,当验证数字或布尔值时,接受可解析为这些基本类型的字符串值是有意义的,因为后续处理也会自动将这些字面值解析为适当的数值和逻辑值。此外,非字符串的基本类型值很容易转换为字符串,所以为什么不允许任何 JSON 基本类型作为字符串呢?

例如,我们看这个模式:

{ "properties": { "booleanProp": { "type": "boolean" }, "integerProp": { "type": "integer" }, "nullProp": { "type": "null" }, "numberProp": { "type": "number" }, "stringProp": { "type": "string" } } }

以下 JSON 文档无法通过验证,尽管所有字符串都可以轻松转换为适当的值:

{ "numberProp": "12.34", "integerProp": "12", "booleanProp": "true", "nullProp": "null", "stringProp": 12.34 }

在这种情况下,如果你希望上述实例能够通过对模式的验证,你需要使用开启了宽松基本类型验证配置。例如:

import org.everit.json.schema.*; ... Validator validator = Validator.builder() .primitiveValidationStrategry(PrimitiveValidationStrategy.LENIENT) .build(); validator.performValidation(schema, input);

注意:在宽松解析模式下,将接受所有 22 种可能的布尔字面值作为逻辑值。

默认值

JSON Schema 规范定义了 "default" 关键字来表示默认值,尽管它没有明确说明这应该如何影响验证过程。默认情况下,这个库不会设置默认值,但如果你需要这个功能,你可以在加载模式之前通过 SchemaLoaderBuilder#useDefaults(boolean) 方法开启它:

{ "properties": { "prop": { "type": "number", "default": 1 } } }
JSONObject input = new JSONObject("{}"); System.out.println(input.get("prop")); // 打印 null Schema schema = SchemaLoader.builder() .useDefaults(true) .schemaJson(rawSchema) .build() .load().build(); schema.validate(input); System.out.println(input.get("prop")); // 打印 1

如果 input 中缺少一些在模式中有 "default" 值的属性,那么验证器在验证过程中会设置这些值。

正则表达式实现

为了支持 JSON Schema 的 "regex" 关键字,该库提供了两种可能的实现:

  • 默认基于 java.util.regex
  • 另一种基于 RE2J

虽然 RE2J 库提供了比 java.util.regex 显著更好的性能,但它与 java.util 或 ECMA 262 支持的语法不完全兼容。因此,如果你关心性能且其局限性可以接受,则推荐使用 RE2J。

可以通过 SchemaLoaderBuilder#regexpFactory() 调用激活 RE2J 实现:

SchemaLoader loader = SchemaLoader.builder() .regexpFactory(new RE2JRegexpFactory()) // ... .build();

注意:

  • 如果你不需要 RE2J 实现,建议在你的 pom.xml 中排除它,以免不必要地增加你的构件大小
  • 版本历史:在 1.0.0 ... 1.7.0 版本中使用了 java.util 实现,在 1.8.0 版本中使用了 RE2J 实现,在 1.9.0 版本中我们使其可配置,因为有一些回归问题的报告。

readOnly 和 writeOnly 上下文

该库支持 readOnlywriteOnly 关键字,这两个关键字首次出现在 Draft 7 中。如果你想使用这个功能,那么在验证之前你需要告诉验证器验证是在读取还是写入上下文中进行的。例如:

schema.json:

{ "properties": { "id": { "type": "number", "readOnly": true } } }

验证代码片段:

Validator validator = Validator.builder() .readWriteContext(ReadWriteContext.WRITE) .build(); validator.performValidation(schema, new JSONObject("{\"id\":42}"));

在这个例子中,我们告诉验证器验证发生在 WRITE 上下文中,而在输入的 JSON 对象中出现了 "id" 属性,该属性在模式中被标记为 "readOnly",因此这个调用将抛出 ValidationException

格式验证器

1.2.0 版本开始,该库支持 ["format" 关键字][draft-fge-json-schema-validation-00 format](这是规范的可选部分)。

支持的格式根据你使用的模式规范版本而有所不同(因为标准格式是在验证规范的不同版本中引入的)。

以下是支持的标准格式的兼容性表格:

Draft 4Draft 6Draft 7
date-time:white_check_mark::white_check_mark::white_check_mark:
email:white_check_mark::white_check_mark::white_check_mark:
hostname:white_check_mark::white_check_mark::white_check_mark:
ipv4:white_check_mark::white_check_mark::white_check_mark:
ipv6:white_check_mark::white_check_mark::white_check_mark:
uri:white_check_mark::white_check_mark::white_check_mark:
uri-reference:white_check_mark::white_check_mark:
uri-template:white_check_mark::white_check_mark:
json-pointer:white_check_mark::white_check_mark:
date:white_check_mark:
time:white_check_mark:
regex:white_check_mark:
relative-json-pointer:white_check_mark:

该库还支持添加自定义格式验证器。要使用自定义验证器,基本上你需要:

  • 在实现 org.everit.json.schema.FormatValidator 接口的类中创建你自己的验证
  • 在加载实际模式之前,在 org.everit.json.schema.loader.SchemaLoader.SchemaLoaderBuilder 实例中将你的验证器绑定到一个名称

示例

假设任务是创建一个自定义验证器,该验证器接受字符数为偶数的字符串。

自定义的 FormatValidator 将看起来像这样:

public class EvenCharNumValidator implements FormatValidator { @Override public Optional<String> validate(final String subject) { if (subject.length() % 2 == 0) { return Optional.empty(); } else { return Optional.of(String.format("字符串 [%s] 的长度为奇数", subject)); } } }

要将 EvenCharNumValidator 绑定到 "format" 值(例如 "evenlength"),你需要在模式加载器配置中将验证器实例绑定到关键字:

JSONObject rawSchema = new JSONObject(new JSONTokener(inputStream)); SchemaLoader schemaLoader = SchemaLoader.builder() .schemaJson(rawSchema) // rawSchema 是使用非标准格式 "evenlength" 的模式的 JSON 表示 .addFormatValidator("evenlength", new EvenCharNumValidator()) // EvenCharNumValidator 被绑定到 "evenlength" 关键字 .build(); Schema schema = schemaLoader.load().build(); // 使用上面创建的配置来创建模式 schema.validate(jsonDocument); // 在这里进行文档验证

$ref 解析

在 JSON Schema 文档中,可以使用相对 URI 来引用之前定义的类型。这些引用使用 "$ref""$id" 关键字表示。虽然规范详细描述了解析范围的改变和解引用,但它并没有解释当第一次出现的 "$ref""$id" 是相对 URI 时的预期行为。

在此实现中,可以使用适当的构建器方法显式定义一个作为基本 URI(解析范围)的绝对 URI:

SchemaLoader schemaLoader = SchemaLoader.builder() .schemaJson(jsonSchema) .resolutionScope("http://example.org/") // 设置默认解析范围 .build();

从类路径加载

随着模式的增长,你会希望将其拆分为多个源文件,并用 "$ref" 引用连接它们。 如果你想将模式存储在类路径上(而不是通过 HTTP 提供),那么推荐的方法是使用 classpath: 协议来让模式相互引用。要使 classpath: 协议工作:

  • 如果你使用 Spring 框架,你不需要做任何事,spring 会自动安装必要的协议处理器
  • 否则,你可以使用库的内置类路径感知 SchemaClient,例如:
SchemaLoader schemaLoader = SchemaLoader.builder() .schemaClient(SchemaClient.classPathAwareClient()) .schemaJson(jsonSchema) .resolutionScope("classpath://my/schemas/directory/") // 设置默认解析范围 .build();

有了这个配置,jsonSchema 中的以下引用将被正确解析:

{ "properties": { "sameDir": { "$ref": "sameDirSchema.json" }, "absPath": { "$ref": "classpath://somewhere/else/otherschema.json" }, "httpPath": { "$ref": "http://example.org/http-works-as-usual" }, } }

sameDirSchema.json 将在类路径的 /my/schemas/directory/sameDirSchema.json 中查找。

通过 URI 注册模式

有时使用预加载的模式很有用,我们可以为这些模式分配一个任意的 URI(可能是 uuid),而不是通过 URL 加载模式。这可以通过模式加载器的 #registerSchemaByURI() 方法将模式分配给 URI 来实现。例如:

SchemaLoader schemaLoader = SchemaLoader.builder() .registerSchemaByURI(new URI("urn:uuid:a773c7a2-1a13-4f6a-a70d-694befe0ce63"), aJSONObject) .registerSchemaByURI(new URI("http://example.org"), otherJSONObject) .schemaJson(jsonSchema) .resolutionScope("classpath://my/schemas/directory/") .build();

注意:

  • 传递的模式对象必须是 JSONObjectBoolean(形式参数类型是 Object 只是因为这两者没有其他共同的超类)。
  • 如果你愿意,你可以传递一个带有 HTTP 协议的 URL,它仍然是一个有效的 URI。在这种情况下,由于你预先将模式分配给了 URI,所以不会进行网络调用。这可以作为一种缓存策略(尽管定义你自己的 SchemaClient 实现也可以,或者你甚至可以利用 java.net 包的可扩展协议处理)

排除依赖项

可以从库中排除一些依赖项,它仍然可用,但有一些限制:

  • 如果你排除了 com.damnhandy:handy-uri-templates 依赖,那么你的模式不应使用 "uri-template" 格式
  • 如果你排除了 commons-validator:commons-validator 依赖,那么你的模式不应使用以下格式: "email", "ipv4", "ipv6", "hostname"

Javadoc

按库版本:

1.0.0 - 1.5.1 版本的生成 javadoc 可在 javadoc.io 上获取

中间版本(1.6.0 - 1.9.1)没有在任何地方发布。 [ASL 2.0 徽章]: https://img.shields.io/:license-Apache%202.0-blue.svg [ASL 2.0]: https://www.apache.org/licenses/LICENSE-2.0 [Travis master分支徽章]: https://travis-ci.org/everit-org/json-schema.svg?branch=master [Travis]: https://travis-ci.org/everit-org/json-schema [Coveralls.io master分支徽章]: https://coveralls.io/repos/github/everit-org/json-schema/badge.svg?branch=master [Coveralls.io]: https://coveralls.io/github/everit-org/json-schema?branch=master [java-json-tools/json-schema-validator]: https://github.com/java-json-tools/json-schema-validator [draft-zyp-json-schema-04]: https://tools.ietf.org/html/draft-zyp-json-schema-04 [draft-fge-json-schema-validation-00 格式]: https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-7

编辑推荐精选

Trae

Trae

字节跳动发布的AI编程神器IDE

Trae是一种自适应的集成开发环境(IDE),通过自动化和多元协作改变开发流程。利用Trae,团队能够更快速、精确地编写和部署代码,从而提高编程效率和项目交付速度。Trae具备上下文感知和代码自动完成功能,是提升开发效率的理想工具。

AI工具TraeAI IDE协作生产力转型热门
问小白

问小白

全能AI智能助手,随时解答生活与工作的多样问题

问小白,由元石科技研发的AI智能助手,快速准确地解答各种生活和工作问题,包括但不限于搜索、规划和社交互动,帮助用户在日常生活中提高效率,轻松管理个人事务。

热门AI助手AI对话AI工具聊天机器人
Transly

Transly

实时语音翻译/同声传译工具

Transly是一个多场景的AI大语言模型驱动的同声传译、专业翻译助手,它拥有超精准的音频识别翻译能力,几乎零延迟的使用体验和支持多国语言可以让你带它走遍全球,无论你是留学生、商务人士、韩剧美剧爱好者,还是出国游玩、多国会议、跨国追星等等,都可以满足你所有需要同传的场景需求,线上线下通用,扫除语言障碍,让全世界的语言交流不再有国界。

讯飞智文

讯飞智文

一键生成PPT和Word,让学习生活更轻松

讯飞智文是一个利用 AI 技术的项目,能够帮助用户生成 PPT 以及各类文档。无论是商业领域的市场分析报告、年度目标制定,还是学生群体的职业生涯规划、实习避坑指南,亦或是活动策划、旅游攻略等内容,它都能提供支持,帮助用户精准表达,轻松呈现各种信息。

AI办公办公工具AI工具讯飞智文AI在线生成PPTAI撰写助手多语种文档生成AI自动配图热门
讯飞星火

讯飞星火

深度推理能力全新升级,全面对标OpenAI o1

科大讯飞的星火大模型,支持语言理解、知识问答和文本创作等多功能,适用于多种文件和业务场景,提升办公和日常生活的效率。讯飞星火是一个提供丰富智能服务的平台,涵盖科技资讯、图像创作、写作辅助、编程解答、科研文献解读等功能,能为不同需求的用户提供便捷高效的帮助,助力用户轻松获取信息、解决问题,满足多样化使用场景。

热门AI开发模型训练AI工具讯飞星火大模型智能问答内容创作多语种支持智慧生活
Spark-TTS

Spark-TTS

一种基于大语言模型的高效单流解耦语音令牌文本到语音合成模型

Spark-TTS 是一个基于 PyTorch 的开源文本到语音合成项目,由多个知名机构联合参与。该项目提供了高效的 LLM(大语言模型)驱动的语音合成方案,支持语音克隆和语音创建功能,可通过命令行界面(CLI)和 Web UI 两种方式使用。用户可以根据需求调整语音的性别、音高、速度等参数,生成高质量的语音。该项目适用于多种场景,如有声读物制作、智能语音助手开发等。

咔片PPT

咔片PPT

AI助力,做PPT更简单!

咔片是一款轻量化在线演示设计工具,借助 AI 技术,实现从内容生成到智能设计的一站式 PPT 制作服务。支持多种文档格式导入生成 PPT,提供海量模板、智能美化、素材替换等功能,适用于销售、教师、学生等各类人群,能高效制作出高品质 PPT,满足不同场景演示需求。

讯飞绘文

讯飞绘文

选题、配图、成文,一站式创作,让内容运营更高效

讯飞绘文,一个AI集成平台,支持写作、选题、配图、排版和发布。高效生成适用于各类媒体的定制内容,加速品牌传播,提升内容营销效果。

热门AI辅助写作AI工具讯飞绘文内容运营AI创作个性化文章多平台分发AI助手
材料星

材料星

专业的AI公文写作平台,公文写作神器

AI 材料星,专业的 AI 公文写作辅助平台,为体制内工作人员提供高效的公文写作解决方案。拥有海量公文文库、9 大核心 AI 功能,支持 30 + 文稿类型生成,助力快速完成领导讲话、工作总结、述职报告等材料,提升办公效率,是体制打工人的得力写作神器。

openai-agents-python

openai-agents-python

OpenAI Agents SDK,助力开发者便捷使用 OpenAI 相关功能。

openai-agents-python 是 OpenAI 推出的一款强大 Python SDK,它为开发者提供了与 OpenAI 模型交互的高效工具,支持工具调用、结果处理、追踪等功能,涵盖多种应用场景,如研究助手、财务研究等,能显著提升开发效率,让开发者更轻松地利用 OpenAI 的技术优势。

下拉加载更多