JSON Schema是基于JSON的格式的规范,用于定义JSON数据的结构。
官网:https://ajv.js.org/json-schema.html
在线验证:https://www.jsonschemavalidator.net/
在json-schema官网上可以看到,java版本的validator库推荐了以下几种方案:
Snow 2019-09, draft-07, -06 Uses Maven for the project and Gson under the hood. (GNU Affero General Public License v3.0)
everit-org/json-schema draft-07, -06, -04 (Apache License 2.0)
Justify draft-07, -06, -04 (Apache License 2.0)
networknt/json-schema-validator draft-07, -06, -04 Support OpenAPI 3.0 with Jackson parser (Apache License 2.0)
常用的json-schema-validator库有:everit-org/json-schema和networknt/json-schema-validator ,在everit-org/json-schema的github介绍中可知,如果项目代码中使用jackson进行的json解析,推荐使用后者进行校验;如果使用的是org.json API 进行json解析,推荐使用前者校验。
everit:GitHub - everit-org/json-schema: JSON Schema validator for java, based on the org.json API
networknt: https://github.com/networknt/json-schema-validator
fge:https://github.com/java-json-tools/json-schema-validator
注意:fge/json-schema-validator也称作 java-json-tools/json-schema-validator
参考:https://blog.csdn.net/liuxiao723846/article/details/108578544
在networknt github上有一个三者的性能对比,最快的是networknt。
fge: 7130ms
everit-org: 1168ms
networknt: 223ms
示例1
{
"type":"object",
"required":[
"client_side_conn_param",
"server_side_conn_param",
"bypass_duplicated_packet"
],
"properties":{
"client_side_conn_param":{
"$ref":"#/$defs/conn_params"
},
"server_side_conn_param":{
"$ref":"#/$defs/conn_params"
},
"bypass_duplicated_packet":{
"type":"integer",
"enum":[
0,
1
]
}
},
"$defs":{
"conn_params":{
"type":"object",
"required":[
"tcp_maxseg",
"nodelay",
"keep_alive",
"ttl",
"user_timeout"
],
"properties":{
"tcp_maxseg":{
"type":"object",
"properties":{
"enable":{
"type":"integer",
"enum":[
0,
1
]
},
"maxseg":{
"type":"integer"
}
},
"if":{
"properties":{
"enable":{
"const":1
}
}
},
"then":{
"properties":{
"maxseg":{
"minimum":536,
"maximum":1460
}
},
"required":[
"maxseg"
]
}
},
"nodelay":{
"type":"integer",
"enum":[
0,
1
]
},
"keep_alive":{
"type":"object",
"required":[
"enable"
],
"properties":{
"enable":{
"type":"integer",
"enum":[
0,
1
]
},
"tcp_keepcnt":{
"type":"integer"
},
"tcp_keepidle":{
"type":"integer"
},
"tcp_keepintvl":{
"type":"integer"
}
},
"if":{
"properties":{
"enable":{
"const":1
}
}
},
"then":{
"properties":{
"tcp_keepcnt":{
"minimum":1,
"maximum":222
},
"tcp_keepidle":{
"minimum":30,
"maximum":7200
},
"tcp_keepintvl":{
"minimum":15,
"maximum":75
}
},
"required":[
"tcp_keepcnt",
"tcp_keepidle",
"tcp_keepintvl"
]
}
},
"ttl":{
"type":"integer",
"minimum":1,
"maximum":255
},
"user_timeout":{
"type":"integer",
"minimum":200,
"maximum":60000
}
}
}
}
}
示例2:array、maxItems、maxLength
{
"type":"object",
"required":[
"method",
"rules"
],
"properties":{
"method":{
"type":"string",
"enum":[
"replace"
]
},
"rules":{
"type":"array",
"maxItems":16,
"items":{
"required":[
"search_in",
"find",
"replace_with"
],
"properties":{
"regex_enable":{
"type":"integer",
"enum":[
0,
1
]
},
"search_in":{
"type":"string"
},
"find":{
"type":"string",
"minLength":1
},
"replace_with":{
"type":"string",
"minLength":1
}
}
}
}
}
}
示例3
{
"type":"object",
"required":[
"method",
"rules"
],
"properties":{
"method":{
"type":"string",
"enum":[
"edit_element"
]
},
"rules":{
"type":"array",
"items":{
"required":[
"anchor_element",
"target_element"
],
"properties":{
"anchor_element":{
"type":"object",
"required":[
"search_scope",
"contained_keyword"
],
"properties":{
"search_scope":{
"type":"string",
"enum":[
"whole_file",
"inside_element"
]
},
"start_indicator":{
"type":"string"
},
"contained_keyword":{
"type":"string"
}
},
"if":{
"properties":{
"search_scope":{
"const":"inside_element"
}
}
},
"then":{
"required":[
"start_indicator"
]
}
},
"target_element":{
"type":"object",
"required":[
"target_distance_from_matching",
"element_treatment"
],
"properties":{
"target_distance_from_matching":{
"type":"integer"
},
"element_treatment":{
"type":"string",
"enum":[
"mark",
"remove"
]
}
}
}
}
}
}
}
}
<dependency>
<groupId>com.networknt</groupId>
<artifactId>json-schema-validator</artifactId>
<version>1.0.76</version>
</dependency>
@Test
public void testNetworknt() {
try {
//可指定版本
JsonSchemaFactory schemaFactory = JsonSchemaFactory
.builder(com.networknt.schema.JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7))
.objectMapper(new ObjectMapper())
.build();
JsonSchema schema = schemaFactory.getSchema(JsonMapper.fromJsonString(replaceSchema, JsonNode.class));
Set<ValidationMessage> validate = schema.validate(JsonMapper.fromJsonString(repData, JsonNode.class));
Iterator<ValidationMessage> iterator = validate.iterator();
while (iterator.hasNext()){
ValidationMessage next = iterator.next();
System.out.println(next.getMessage());
}
}catch(Exception e ){
e.printStackTrace();
}
}
示例3在验证下述json时,使用V202012版本,anchor_element.search_scope的value不在枚举列表中未报异常,但V7版本可以。
Networknt要求使用的jaskson的版本在2.12.1以上,否则部分Json Schema属性无法使用,如maxItems、minLength。详见:https://github.com/networknt/json-schema-validator/issues/469
异常信息:
14:43:19.498 [main] DEBUG com.networknt.schema.PropertiesValidator - validate( {"name":"o"}, {"name":"o"}, $)
14:43:19.499 [main] WARN com.networknt.schema.JsonMetaSchema - Could not load validator minLength
com.networknt.schema.JsonSchemaException: java.lang.NoSuchMethodError: com.fasterxml.jackson.databind.JsonNode.canConvertToExactIntegral()Z
at com.networknt.schema.JsonMetaSchema.newValidator(JsonMetaSchema.java:293)
at com.networknt.schema.ValidationContext.newValidator(ValidationContext.java:57)
at com.networknt.schema.JsonSchema.read(JsonSchema.java:236)
at com.networknt.schema.JsonSchema.getValidators(JsonSchema.java:524)
at com.networknt.schema.JsonSchema.validate(JsonSchema.java:315)
at com.networknt.schema.PropertiesValidator.validate(PropertiesValidator.java:69)
at com.networknt.schema.JsonSchema.validate(JsonSchema.java:316)
at com.networknt.schema.JsonSchema.validate(JsonSchema.java:299)
at cn.nis.ntc.JsonValidate.testNetworknt(JsonValidate.java:92)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53)
Caused by: java.lang.NoSuchMethodError: com.fasterxml.jackson.databind.JsonNode.canConvertToExactIntegral()Z