Tencent / rapidjson

A fast JSON parser/generator for C++ with both SAX/DOM style API
http://rapidjson.org/
Other
14.19k stars 3.53k forks source link

schema校验时,必选字段未填,校验通过(During schema validation, the required fields were not filled in, and the validation passed) #2212

Closed Ssscy closed 11 months ago

Ssscy commented 11 months ago

schema.json文件内容如下: The “schema.json” file content is as follows:

{
    "type": "object",
    "additionalProperties": false,
    "required": [
        "port"
    ],
    "properties": {
        "port": {
            "type": "string",
            "enum": [
                "src",
                "dst"
            ],
            "default": "src"
        }
    }
}

test.json文件内容如下: The “test.json” file content is as follows: {}

去掉json schema中port下的default后,可以校验,但是只提示了keyword;required,具体哪个必选字段却不提示 After removing the "default" under "port" in the schema, it can be verified, but only prompts for keyword: "Required", which specific mandatory field is not prompted

Invalid schema: # Invalid keyword: required Invalid document: #

代码如下:

#include <fstream>
#include <iostream>

#include "rapidjson/document.h"
#include "rapidjson/filereadstream.h"
#include "rapidjson/schema.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/writer.h"

using namespace std;
using namespace rapidjson;

int main() {
    std::fstream file;
    std::string test_json = "";

    file.open("test.json", ios::in);
    std::string tmp = "";
    while (getline(file, tmp)) {
        test_json += tmp;
    }
    file.close();

    std::string schema_json = "";
    file.open("schema.json", ios::in);
    tmp = "";
    while (getline(file, tmp)) {
        schema_json += tmp;
    }
    file.close();

    // 解析json
    Document test_doc;
    if (test_doc.Parse(test_json.c_str()).HasParseError()) {
        printf("test_json is not json\n");
        return false;
    }

    Document schema_doc;
    if (schema_doc.Parse(schema_json.c_str()).HasParseError()) {
        printf("schema_json is not json\n");
        return false;
    }

    // 校验json
    SchemaDocument schema(schema_doc);
    SchemaValidator validator(schema);
    if (!test_doc.Accept(validator)) {
        StringBuffer sb;
        validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
        printf("Invalid schema: %s\n", sb.GetString());
        printf("Invalid keyword: %s\n", validator.GetInvalidSchemaKeyword());
        //printf(Invalid code: %d\n", validator.GetInvalidSchemaCode());
        //printf("Invalid message: %s\n", GetValidateError_En(validator.GetInvalidSchemaCode()));
        sb.Clear();
        validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
        printf("Invalid document: %s\n", sb.GetString());
        return false;
    }

    return 0;
}

看了源码发现在schema.h里做完必选字段校验后又增加了对string类型的默认值长度defaultValueLength_判断, 以下两次提交,增加了该判断: 6f7dcb30d9d662bada0e7e2ebd75846b8c5b91f3 fa98b5b4b67af335655a8b6843a9d82ae4b731a5

    bool EndObject(Context& context, SizeType memberCount) const {
        RAPIDJSON_SCHEMA_PRINT(Method, "Schema::EndObject");
        if (hasRequired_) {
            context.error_handler.StartMissingProperties();
            for (SizeType index = 0; index < propertyCount_; index++)
                if (properties_[index].required && !context.propertyExist[index])
                    if (properties_[index].schema->defaultValueLength_ == 0 )
                        context.error_handler.AddMissingProperty(properties_[index].name);
            if (context.error_handler.EndMissingProperties())
                RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorRequired);
        }
    ....
   }

代码为什么只跳过了字符串类型的必选字段,如果含默认值就不报错? 去掉默认值判断后,为何仍无法获取到根节点具体哪个schema字段校验失败?

Ssscy commented 11 months ago

在example/schemavalidator/schemavalidator.cpp中找到了可以获取到根节点具体出错信息的方法