make default-values work for stacked $refs

This commit is contained in:
Patrick Boettcher 2021-12-10 16:16:12 +01:00
parent afe3cc1555
commit 40f5d293fa
3 changed files with 33 additions and 42 deletions

View File

@ -34,12 +34,11 @@ using namespace nlohmann::json_schema;
namespace namespace
{ {
static const json EmptyDefault = nullptr;
class schema class schema
{ {
protected: protected:
root_schema *root_; root_schema *root_;
json default_value_ = nullptr;
public: public:
virtual ~schema() = default; virtual ~schema() = default;
@ -49,11 +48,13 @@ public:
virtual void validate(const json::json_pointer &ptr, const json &instance, json_patch &patch, error_handler &e) const = 0; virtual void validate(const json::json_pointer &ptr, const json &instance, json_patch &patch, error_handler &e) const = 0;
virtual const json &defaultValue(const json::json_pointer &, const json &, error_handler &) const virtual const json &default_value(const json::json_pointer &, const json &, error_handler &) const
{ {
return EmptyDefault; return default_value_;
} }
void set_default_value(const json &v) { default_value_ = v; }
static std::shared_ptr<schema> make(json &schema, static std::shared_ptr<schema> make(json &schema,
root_schema *root, root_schema *root,
const std::vector<std::string> &key, const std::vector<std::string> &key,
@ -75,16 +76,18 @@ class schema_ref : public schema
e.error(ptr, instance, "unresolved or freed schema-reference " + id_); e.error(ptr, instance, "unresolved or freed schema-reference " + id_);
} }
const json &defaultValue(const json::json_pointer &ptr, const json &instance, error_handler &e) const override const json &default_value(const json::json_pointer &ptr, const json &instance, error_handler &e) const override final
{ {
auto target = target_.lock(); if (!default_value_.is_null())
return default_value_;
auto target = target_.lock();
if (target) if (target)
return target->defaultValue(ptr, instance, e); return target->default_value(ptr, instance, e);
else
e.error(ptr, instance, "unresolved or freed schema-reference " + id_); e.error(ptr, instance, "unresolved or freed schema-reference " + id_);
return EmptyDefault; return default_value_;
} }
public: public:
@ -347,9 +350,9 @@ class logical_not : public schema
e.error(ptr, instance, "the subschema has succeeded, but it is required to not validate"); e.error(ptr, instance, "the subschema has succeeded, but it is required to not validate");
} }
const json &defaultValue(const json::json_pointer &ptr, const json &instance, error_handler &e) const override const json &default_value(const json::json_pointer &ptr, const json &instance, error_handler &e) const override
{ {
return subschema_->defaultValue(ptr, instance, e); return subschema_->default_value(ptr, instance, e);
} }
public: public:
@ -443,7 +446,6 @@ bool logical_combination<oneOf>::is_validate_complete(const json &instance, cons
class type_schema : public schema class type_schema : public schema
{ {
json defaultValue_ = EmptyDefault;
std::vector<std::shared_ptr<schema>> type_; std::vector<std::shared_ptr<schema>> type_;
std::pair<bool, json> enum_, const_; std::pair<bool, json> enum_, const_;
std::vector<std::shared_ptr<schema>> logic_; std::vector<std::shared_ptr<schema>> logic_;
@ -456,11 +458,6 @@ class type_schema : public schema
std::shared_ptr<schema> if_, then_, else_; std::shared_ptr<schema> if_, then_, else_;
const json &defaultValue(const json::json_pointer &, const json &, error_handler &) const override
{
return defaultValue_;
}
void validate(const json::json_pointer &ptr, const json &instance, json_patch &patch, error_handler &e) const override final void validate(const json::json_pointer &ptr, const json &instance, json_patch &patch, error_handler &e) const override final
{ {
// depending on the type of instance run the type specific validator - if present // depending on the type of instance run the type specific validator - if present
@ -551,9 +548,10 @@ public:
sch.erase(attr); sch.erase(attr);
} }
const auto default_attr = sch.find("default"); attr = sch.find("default");
if (default_attr != sch.end()) { if (attr != sch.end()) {
defaultValue_ = default_attr.value(); set_default_value(attr.value());
sch.erase(attr);
} }
for (auto &key : known_keywords) for (auto &key : known_keywords)
@ -630,11 +628,6 @@ public:
sch.erase(attr); sch.erase(attr);
} }
} }
void set_default_value(const json &default_value)
{
defaultValue_ = default_value;
}
}; };
class string : public schema class string : public schema
@ -986,9 +979,9 @@ class object : public schema
for (auto const &prop : properties_) { for (auto const &prop : properties_) {
const auto finding = instance.find(prop.first); const auto finding = instance.find(prop.first);
if (instance.end() == finding) { // if the prop is not in the instance if (instance.end() == finding) { // if the prop is not in the instance
const auto &defaultValue = prop.second->defaultValue(ptr, instance, e); const auto &default_value = prop.second->default_value(ptr, instance, e);
if (!defaultValue.is_null()) { // if default value is available if (!default_value.is_null()) { // if default value is available
patch.add((ptr / prop.first), defaultValue); patch.add((ptr / prop.first), default_value);
} }
} }
} }
@ -1282,23 +1275,21 @@ std::shared_ptr<schema> schema::make(json &schema,
auto id = uris.back().derive(attr.value().get<std::string>()); auto id = uris.back().derive(attr.value().get<std::string>());
sch = root->get_or_create_ref(id); sch = root->get_or_create_ref(id);
const auto default_attr = schema.find("default");
if (default_attr != schema.end()) {
if (type_schema *type_sch = dynamic_cast<type_schema *>(sch.get())) {
// copy the referenced schema and modify the default value
auto schema_copy = std::make_shared<type_schema>(*type_sch);
schema_copy->set_default_value(default_attr.value());
sch = schema_copy;
}
}
schema.erase(attr); schema.erase(attr);
// special case where break draft-7 and allow overriding of properties when a $ref is used
attr = schema.find("default");
if (attr != schema.end()) {
// copy the referenced schema and modify the default value
sch = std::make_shared<schema_ref>(*dynamic_cast<schema_ref *>(sch.get()));
sch->set_default_value(attr.value());
schema.erase(attr);
}
} else { } else {
sch = std::make_shared<type_schema>(schema, root, uris); sch = std::make_shared<type_schema>(schema, root, uris);
} }
schema.erase("$schema"); schema.erase("$schema");
schema.erase("default");
schema.erase("title"); schema.erase("title");
schema.erase("description"); schema.erase("description");
} else { } else {

View File

@ -16,7 +16,7 @@ static const json quad_schema = R"(
"height": { "height": {
"$ref": "#/definitions/length" "$ref": "#/definitions/length"
}, },
"depths": { "depth": {
"$ref": "default_schema#/definitions/defaultLength" "$ref": "default_schema#/definitions/defaultLength"
} }
}, },