【问题标题】:Validate JSON schema compliance with Jackson against an external schema file根据外部模式文件验证 JSON 模式是否符合 Jackson
【发布时间】:2015-09-19 15:49:06
【问题描述】:

我想使用 Jackson 库 (https://github.com/FasterXML/jackson) 来处理 Java 中的 JSON 文件,这些文件由 JSON 模式文件描述。

现在,我想验证解析后的 JSON 是否符合由自身解析的 JSON 模式文件。

杰克逊 (https://github.com/FasterXML/jackson-module-jsonSchema) 有一个 JSON 模式模块。但是,在我看来,它的主要关注点是创建从 Java 中创建的 JSON 模式文件。

在 Java 中验证 JSON 模式的好方法是什么? - 最好使用 Jackson,但我也愿意接受其他解决方案。

【问题讨论】:

    标签: java json jackson jsonschema


    【解决方案1】:

    据我所知,Jackson 只能为给定类型生成模式,但不能进行验证。有json-schema-validator,但不再维护。

    【讨论】:

    【解决方案2】:

    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 DB 中。

    @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...
    }
    

    【讨论】:

      【解决方案3】:

      刚刚偶然发现https://github.com/leadpony/justify json 模式验证器的另一个实现,也是最近的草稿版本。 (7,6,4)

      【讨论】:

        【解决方案4】:

        here 所述,jackson 验证器的功能开发已停止。

        但是,到目前为止,我发现networknt 的 json 模式验证器非常活跃和有趣。您可以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
        

        }

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-09-24
          • 1970-01-01
          • 2011-02-06
          • 2016-12-20
          • 1970-01-01
          相关资源
          最近更新 更多