Project Icon

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 验证器

弃用通知

该库目前处于维护模式,已被 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

项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

豆包 MarsCode 是一款革命性的编程助手,通过AI技术提供代码补全、单测生成、代码解释和智能问答等功能,支持100+编程语言,与主流编辑器无缝集成,显著提升开发效率和代码质量。

Project Cover

AI写歌

Suno AI是一个革命性的AI音乐创作平台,能在短短30秒内帮助用户创作出一首完整的歌曲。无论是寻找创作灵感还是需要快速制作音乐,Suno AI都是音乐爱好者和专业人士的理想选择。

Project Cover

有言AI

有言平台提供一站式AIGC视频创作解决方案,通过智能技术简化视频制作流程。无论是企业宣传还是个人分享,有言都能帮助用户快速、轻松地制作出专业级别的视频内容。

Project Cover

Kimi

Kimi AI助手提供多语言对话支持,能够阅读和理解用户上传的文件内容,解析网页信息,并结合搜索结果为用户提供详尽的答案。无论是日常咨询还是专业问题,Kimi都能以友好、专业的方式提供帮助。

Project Cover

阿里绘蛙

绘蛙是阿里巴巴集团推出的革命性AI电商营销平台。利用尖端人工智能技术,为商家提供一键生成商品图和营销文案的服务,显著提升内容创作效率和营销效果。适用于淘宝、天猫等电商平台,让商品第一时间被种草。

Project Cover

吐司

探索Tensor.Art平台的独特AI模型,免费访问各种图像生成与AI训练工具,从Stable Diffusion等基础模型开始,轻松实现创新图像生成。体验前沿的AI技术,推动个人和企业的创新发展。

Project Cover

SubCat字幕猫

SubCat字幕猫APP是一款创新的视频播放器,它将改变您观看视频的方式!SubCat结合了先进的人工智能技术,为您提供即时视频字幕翻译,无论是本地视频还是网络流媒体,让您轻松享受各种语言的内容。

Project Cover

美间AI

美间AI创意设计平台,利用前沿AI技术,为设计师和营销人员提供一站式设计解决方案。从智能海报到3D效果图,再到文案生成,美间让创意设计更简单、更高效。

Project Cover

AIWritePaper论文写作

AIWritePaper论文写作是一站式AI论文写作辅助工具,简化了选题、文献检索至论文撰写的整个过程。通过简单设定,平台可快速生成高质量论文大纲和全文,配合图表、参考文献等一应俱全,同时提供开题报告和答辩PPT等增值服务,保障数据安全,有效提升写作效率和论文质量。

投诉举报邮箱: service@vectorlightyear.com
@2024 懂AI·鲁ICP备2024100362号-6·鲁公网安备37021002001498号