针对外部架构文件验证 JSON 架构是否符合 Jackson
Validate JSON schema compliance with Jackson against an external schema file
我想使用 Jackson 库 (https://github.com/FasterXML/jackson) 处理 Java 中的 JSON 文件,这些文件由 JSON 模式文件描述。
现在,我想验证一个已解析的 JSON 是否符合 JSON 模式文件,该文件由其自身解析。
Jackson (https://github.com/FasterXML/jackson-module-jsonSchema) 有一个 JSON 架构模块。但是,在我看来,它的主要重点是从 Java.
中 创建 一个 JSON 模式文件
在 Java 中验证 JSON 架构的好方法是什么? - 最好使用 Jackson,但我也愿意接受其他解决方案。
据我所知,Jackson 只能为给定类型生成模式,但不能进行验证。有json-schema-validator但不再维护
1.) 添加依赖项 pom.xml :-
<dependency>
<groupId>com.github.fge</groupId>
<artifactId>json-schema-validator</artifactId>
<version>2.2.6</version>
</dependency>
2.) NoSqlEntity 是实体的元数据,可以驻留在 no-sql 数据库中。
已使用架构文件初始化 NoSqlEntity。
public static final NoSqlEntity entity = new
NoSqlEntity("PAYOUT_ENTITY", "DB_","/schema/payout_entity.json");
public class NoSqlEntity {
private static final Map<String, NoSqlEntity> STORE = new HashMap<>();
private final AtomicLong seq = new AtomicLong(System.currentTimeMillis());
private IdentityGenerator identityGenerator;
private String entity;
private String collectionName;
private String jsonSchema;
private String idColumn = "id";
private String database;
public NoSqlEntity(String entity, String idColumn, String collectionPrefix, String jsonSchema) {
this.entity = entity;
this.idColumn = idColumn;
this.collectionName = collectionPrefix + "_" + entity;
this.jsonSchema = jsonSchema;
STORE.put(entity, this);
}
public NoSqlEntity(String collectionName, String jsonSchema) {
this.collectionName = collectionName;
this.jsonSchema = jsonSchema;
}
public static NoSqlEntity valueOf(String entityType) {
return STORE.get(entityType);
}
public boolean isNotNullSchema() {
return jsonSchema != null;
}
...
// Other Getter/Setter properties and methods.
}
3.) payout_entity.json-
的验证模式文件格式示例
{
"properties":{
"txId":{"type":"string"}
}
"required" :["txId","currency"]
}
4.) JsonSchemaManager - 验证传入的 JSON 模式并缓存该模式。
public class JsonSchemaManager {
private final static Logger LOGGER = LoggerFactory.getLogger(JsonSchemaManager.class);
protected final static String LS = StandardSystemProperty.LINE_SEPARATOR.value();
private final JsonValidator validator = JsonSchemaFactory.byDefault().getValidator();
private final Map<NoSqlEntity, JsonNode> schemaMap = new HashMap<>();
public JsonNode load(NoSqlEntity noSqlEntity) throws IOException {
final JsonNode schema = JsonLoader.fromURL(this.getClass().getResource(noSqlEntity.getJsonSchema()));
schemaMap.put(noSqlEntity, schema);
return schema;
}
public void validateSchema(NoSqlEntity noSqlEntity, JsonNode toBeValidated, Consumer<ProcessingReport> consumer) {
try {
JsonNode schema = schemaMap.get(noSqlEntity);
if (schema == null) {
schema = load(noSqlEntity);
}
final ProcessingReport report = validator.validate(schema, toBeValidated);
if (!report.isSuccess()) {
consumer.accept(report);
}
} catch (IOException ex) { //NOSONAR
throw new InvalidRequestException(ex.toString());
} catch (ProcessingException ex) { //NOSONAR
throw new InvalidRequestException(ex.toString());
}
}
public synchronized boolean synchronizedCheck(NoSqlEntity noSqlEntity, JsonNode toBeValidated, Consumer<Map<String, Object>> messageConsumers) {
boolean flags = CommonUtils.unchecked(() -> {
validateSchema(noSqlEntity, toBeValidated, report -> {
report.forEach(processingMessage -> messageConsumers.accept(JsonConverter.jsonAsMapObject(processingMessage.asJson())));
});
return true;
}, ex -> {
throw new RuntimeException(ex.toString()); //NOSONAR
});
return flags;
}
}
5.) NoSqlRepository 将元数据保存到 NoSql 数据库中。
@Component
public class NoSqlRepository {
private static final Logger LOGGER = LoggerFactory.getLogger(NoSqlRepository.class);
private final DocumentFormat documentFormat = DocumentFormat.JSON;
private static final String SEPARATOR = ",";
private static final ThreadLocal<MyLocalVariable> THREAD_LOCAL_VARIABLES = ThreadLocal.withInitial(() -> new MyLocalVariable());
static class MyLocalVariable {
private JsonSchemaManager schemaManager = new JsonSchemaManager();
private BasicBSONDecoder bsonDecoder = new BasicBSONDecoder();
public JsonSchemaManager getSchemaManager() {
return schemaManager;
}
public BasicBSONDecoder getBsonDecoder() {
return bsonDecoder;
}
}
private void checkSchemaIfAny(NoSqlEntity noSqlEntity, JsonNode entity) {
if (noSqlEntity.isNotNullSchema()) {
THREAD_LOCAL_VARIABLES.get().getSchemaManager().check(noSqlEntity, entity);
}
}
public String saveEntity(NoSqlEntity noSqlEntity, JsonNode entity){
// Before persisting payload into noSQL, validate payload against schema.
this.checkSchemaIfAny(noSqlEntity,entity);
}
// Other CURD methods here...
}
刚刚偶然发现 https://github.com/leadpony/justify json 模式验证器的另一个实现,也是更新的草稿版本。 (7,6,4)
如here所述,jackson验证器的功能开发已经停止。
不过,我发现 networknt's json schema validator much live and interesting as of now. You can refer 这些内容是为了快速入门。
Maven 依赖
<dependency>
<groupId>com.networknt</groupId>
<artifactId>json-schema-validator</artifactId>
<version>1.0.49</version>
</dependency>
代码片段 -
String jsonOrder = SampleUtil.getSampleJsonOrder();//replace or write
System.out.println(jsonOrder);
//Read json schema from classpaht
JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7);
InputStream is = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("order-schema.json");
JsonSchema schema = factory.getSchema(is);
//Read json to validate
try {
JsonNode node = mapper.readTree(jsonOrder);
Set<ValidationMessage> errors = schema.validate(node);
System.out.println("Errors in first json object: " + errors);
} catch (IOException e) {
e.printStackTrace();
}
//Test for invalid json
String emptyFoIdOrder = "{\"gtins\":[\"1\",\"2\",\"3\",\"4\"],\"storeId\":121,\"deliveryAddress\":\"Any street, some house - PIN 2021\"}/";
try {
JsonNode node = mapper.readTree(emptyFoIdOrder);
Set<ValidationMessage> errors = schema.validate(node);
System.out.println("Errors in first json object: " + errors);
} catch (IOException e) {
e.printStackTrace();
}
示例 Json 使用的方案-
{
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "http://example.com/example.json",
"type": "object",
"title": "The root schema",
"description": "The root schema comprises the entire JSON document.",
"default": {},
"examples": [
{
"foId": "9876",
"gtins": [
"1",
"2",
"3",
"4"
],
"storeId": 121,
"deliveryAddress": "Any streeam, some house - PIN 2021"
}
],
"required": [
"foId",
"gtins",
"storeId",
"deliveryAddress"
],
"properties": {
"foId": {
"$id": "#/properties/foId",
"type": "string",
"title": "The foId schema",
"description": "An explanation about the purpose of this instance.",
"default": "",
"examples": [
"9876"
]
},
"gtins": {
"$id": "#/properties/gtins",
"type": "array",
"title": "The gtins schema",
"description": "An explanation about the purpose of this instance.",
"default": [],
"examples": [
[
"1",
"2"
]
],
"additionalItems": true,
"items": {
"$id": "#/properties/gtins/items",
"anyOf": [
{
"$id": "#/properties/gtins/items/anyOf/0",
"type": "string",
"title": "The first anyOf schema",
"description": "An explanation about the purpose of this instance.",
"default": "",
"examples": [
"1",
"2"
]
}
]
}
},
"storeId": {
"$id": "#/properties/storeId",
"type": "integer",
"title": "The storeId schema",
"description": "An explanation about the purpose of this instance.",
"default": 0,
"examples": [
121
]
},
"deliveryAddress": {
"$id": "#/properties/deliveryAddress",
"type": "string",
"title": "The deliveryAddress schema",
"description": "An explanation about the purpose of this instance.",
"default": "",
"examples": [
"Any streeam, some house - PIN 2021"
]
}
},
"additionalProperties": true
}
我想使用 Jackson 库 (https://github.com/FasterXML/jackson) 处理 Java 中的 JSON 文件,这些文件由 JSON 模式文件描述。
现在,我想验证一个已解析的 JSON 是否符合 JSON 模式文件,该文件由其自身解析。
Jackson (https://github.com/FasterXML/jackson-module-jsonSchema) 有一个 JSON 架构模块。但是,在我看来,它的主要重点是从 Java.
中 创建 一个 JSON 模式文件在 Java 中验证 JSON 架构的好方法是什么? - 最好使用 Jackson,但我也愿意接受其他解决方案。
据我所知,Jackson 只能为给定类型生成模式,但不能进行验证。有json-schema-validator但不再维护
1.) 添加依赖项 pom.xml :-
<dependency>
<groupId>com.github.fge</groupId>
<artifactId>json-schema-validator</artifactId>
<version>2.2.6</version>
</dependency>
2.) NoSqlEntity 是实体的元数据,可以驻留在 no-sql 数据库中。
已使用架构文件初始化 NoSqlEntity。
public static final NoSqlEntity entity = new NoSqlEntity("PAYOUT_ENTITY", "DB_","/schema/payout_entity.json");
public class NoSqlEntity {
private static final Map<String, NoSqlEntity> STORE = new HashMap<>();
private final AtomicLong seq = new AtomicLong(System.currentTimeMillis());
private IdentityGenerator identityGenerator;
private String entity;
private String collectionName;
private String jsonSchema;
private String idColumn = "id";
private String database;
public NoSqlEntity(String entity, String idColumn, String collectionPrefix, String jsonSchema) {
this.entity = entity;
this.idColumn = idColumn;
this.collectionName = collectionPrefix + "_" + entity;
this.jsonSchema = jsonSchema;
STORE.put(entity, this);
}
public NoSqlEntity(String collectionName, String jsonSchema) {
this.collectionName = collectionName;
this.jsonSchema = jsonSchema;
}
public static NoSqlEntity valueOf(String entityType) {
return STORE.get(entityType);
}
public boolean isNotNullSchema() {
return jsonSchema != null;
}
...
// Other Getter/Setter properties and methods.
}
3.) payout_entity.json-
的验证模式文件格式示例 {
"properties":{
"txId":{"type":"string"}
}
"required" :["txId","currency"]
}
4.) JsonSchemaManager - 验证传入的 JSON 模式并缓存该模式。
public class JsonSchemaManager {
private final static Logger LOGGER = LoggerFactory.getLogger(JsonSchemaManager.class);
protected final static String LS = StandardSystemProperty.LINE_SEPARATOR.value();
private final JsonValidator validator = JsonSchemaFactory.byDefault().getValidator();
private final Map<NoSqlEntity, JsonNode> schemaMap = new HashMap<>();
public JsonNode load(NoSqlEntity noSqlEntity) throws IOException {
final JsonNode schema = JsonLoader.fromURL(this.getClass().getResource(noSqlEntity.getJsonSchema()));
schemaMap.put(noSqlEntity, schema);
return schema;
}
public void validateSchema(NoSqlEntity noSqlEntity, JsonNode toBeValidated, Consumer<ProcessingReport> consumer) {
try {
JsonNode schema = schemaMap.get(noSqlEntity);
if (schema == null) {
schema = load(noSqlEntity);
}
final ProcessingReport report = validator.validate(schema, toBeValidated);
if (!report.isSuccess()) {
consumer.accept(report);
}
} catch (IOException ex) { //NOSONAR
throw new InvalidRequestException(ex.toString());
} catch (ProcessingException ex) { //NOSONAR
throw new InvalidRequestException(ex.toString());
}
}
public synchronized boolean synchronizedCheck(NoSqlEntity noSqlEntity, JsonNode toBeValidated, Consumer<Map<String, Object>> messageConsumers) {
boolean flags = CommonUtils.unchecked(() -> {
validateSchema(noSqlEntity, toBeValidated, report -> {
report.forEach(processingMessage -> messageConsumers.accept(JsonConverter.jsonAsMapObject(processingMessage.asJson())));
});
return true;
}, ex -> {
throw new RuntimeException(ex.toString()); //NOSONAR
});
return flags;
}
}
5.) NoSqlRepository 将元数据保存到 NoSql 数据库中。
@Component
public class NoSqlRepository {
private static final Logger LOGGER = LoggerFactory.getLogger(NoSqlRepository.class);
private final DocumentFormat documentFormat = DocumentFormat.JSON;
private static final String SEPARATOR = ",";
private static final ThreadLocal<MyLocalVariable> THREAD_LOCAL_VARIABLES = ThreadLocal.withInitial(() -> new MyLocalVariable());
static class MyLocalVariable {
private JsonSchemaManager schemaManager = new JsonSchemaManager();
private BasicBSONDecoder bsonDecoder = new BasicBSONDecoder();
public JsonSchemaManager getSchemaManager() {
return schemaManager;
}
public BasicBSONDecoder getBsonDecoder() {
return bsonDecoder;
}
}
private void checkSchemaIfAny(NoSqlEntity noSqlEntity, JsonNode entity) {
if (noSqlEntity.isNotNullSchema()) {
THREAD_LOCAL_VARIABLES.get().getSchemaManager().check(noSqlEntity, entity);
}
}
public String saveEntity(NoSqlEntity noSqlEntity, JsonNode entity){
// Before persisting payload into noSQL, validate payload against schema.
this.checkSchemaIfAny(noSqlEntity,entity);
}
// Other CURD methods here...
}
刚刚偶然发现 https://github.com/leadpony/justify json 模式验证器的另一个实现,也是更新的草稿版本。 (7,6,4)
如here所述,jackson验证器的功能开发已经停止。
不过,我发现 networknt's json schema validator much live and interesting as of now. You can refer 这些内容是为了快速入门。
Maven 依赖
<dependency>
<groupId>com.networknt</groupId>
<artifactId>json-schema-validator</artifactId>
<version>1.0.49</version>
</dependency>
代码片段 -
String jsonOrder = SampleUtil.getSampleJsonOrder();//replace or write
System.out.println(jsonOrder);
//Read json schema from classpaht
JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7);
InputStream is = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("order-schema.json");
JsonSchema schema = factory.getSchema(is);
//Read json to validate
try {
JsonNode node = mapper.readTree(jsonOrder);
Set<ValidationMessage> errors = schema.validate(node);
System.out.println("Errors in first json object: " + errors);
} catch (IOException e) {
e.printStackTrace();
}
//Test for invalid json
String emptyFoIdOrder = "{\"gtins\":[\"1\",\"2\",\"3\",\"4\"],\"storeId\":121,\"deliveryAddress\":\"Any street, some house - PIN 2021\"}/";
try {
JsonNode node = mapper.readTree(emptyFoIdOrder);
Set<ValidationMessage> errors = schema.validate(node);
System.out.println("Errors in first json object: " + errors);
} catch (IOException e) {
e.printStackTrace();
}
示例 Json 使用的方案-
{
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "http://example.com/example.json",
"type": "object",
"title": "The root schema",
"description": "The root schema comprises the entire JSON document.",
"default": {},
"examples": [
{
"foId": "9876",
"gtins": [
"1",
"2",
"3",
"4"
],
"storeId": 121,
"deliveryAddress": "Any streeam, some house - PIN 2021"
}
],
"required": [
"foId",
"gtins",
"storeId",
"deliveryAddress"
],
"properties": {
"foId": {
"$id": "#/properties/foId",
"type": "string",
"title": "The foId schema",
"description": "An explanation about the purpose of this instance.",
"default": "",
"examples": [
"9876"
]
},
"gtins": {
"$id": "#/properties/gtins",
"type": "array",
"title": "The gtins schema",
"description": "An explanation about the purpose of this instance.",
"default": [],
"examples": [
[
"1",
"2"
]
],
"additionalItems": true,
"items": {
"$id": "#/properties/gtins/items",
"anyOf": [
{
"$id": "#/properties/gtins/items/anyOf/0",
"type": "string",
"title": "The first anyOf schema",
"description": "An explanation about the purpose of this instance.",
"default": "",
"examples": [
"1",
"2"
]
}
]
}
},
"storeId": {
"$id": "#/properties/storeId",
"type": "integer",
"title": "The storeId schema",
"description": "An explanation about the purpose of this instance.",
"default": 0,
"examples": [
121
]
},
"deliveryAddress": {
"$id": "#/properties/deliveryAddress",
"type": "string",
"title": "The deliveryAddress schema",
"description": "An explanation about the purpose of this instance.",
"default": "",
"examples": [
"Any streeam, some house - PIN 2021"
]
}
},
"additionalProperties": true
}