From 4f67636760f55f652c580b4a8d835513b5645f9e Mon Sep 17 00:00:00 2001
From: Patrick Boettcher
Date: Mon, 27 Jun 2022 10:30:11 +0200
Subject: [PATCH] ref-schema: create a new ref-schema when default-value is
present
Default-values on schemas with a $ref field are now stored within
a new reference schema which links to the original reference schema.
It contains the default value and keeps a strong reference (shared_ptr)
to the original reference.
Fixes #209
---
src/json-validator.cpp | 22 +++++++++++++++++-----
test/issue-209/CMakeLists.txt | 3 +++
test/issue-209/color.schema.json | 8 ++++++++
test/issue-209/entities.schema.json | 16 ++++++++++++++++
test/issue-209/instance.json | 10 ++++++++++
5 files changed, 54 insertions(+), 5 deletions(-)
create mode 100644 test/issue-209/CMakeLists.txt
create mode 100644 test/issue-209/color.schema.json
create mode 100644 test/issue-209/entities.schema.json
create mode 100644 test/issue-209/instance.json
diff --git a/src/json-validator.cpp b/src/json-validator.cpp
index 1a801bd..3ffd087 100644
--- a/src/json-validator.cpp
+++ b/src/json-validator.cpp
@@ -65,6 +65,8 @@ class schema_ref : public schema
{
const std::string id_;
std::weak_ptr target_;
+ std::shared_ptr target_strong_; // for references to references keep also the shared_ptr because
+ // no one else might use it after resolving
void validate(const json::json_pointer &ptr, const json &instance, json_patch &patch, error_handler &e) const final
{
@@ -95,7 +97,13 @@ public:
: schema(root), id_(id) {}
const std::string &id() const { return id_; }
- void set_target(const std::shared_ptr &target) { target_ = target; }
+
+ void set_target(const std::shared_ptr &target, bool strong = false)
+ {
+ target_ = target;
+ if (strong)
+ target_strong_ = target;
+ }
};
} // namespace
@@ -1277,13 +1285,17 @@ std::shared_ptr schema::make(json &schema,
schema.erase(attr);
- // special case where break draft-7 and allow overriding of properties when a $ref is used
+ // special case where we 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 depending on the underlying type and modify the default value
- if (auto *ref_sch = dynamic_cast(sch.get())) {
- sch = std::make_shared(*ref_sch);
- sch->set_default_value(attr.value());
+ if (dynamic_cast(sch.get())) {
+ // create a new reference schema use the original reference (which will be resolved later)
+ // to store this overloaed default value #209
+ auto overloaded_ref_sch = std::make_shared(uris[0].to_string(), root);
+ overloaded_ref_sch->set_target(sch, true);
+ overloaded_ref_sch->set_default_value(attr.value());
+ sch = overloaded_ref_sch;
} else if (auto *type_sch = dynamic_cast(sch.get())) {
sch = std::make_shared(*type_sch);
sch->set_default_value(attr.value());
diff --git a/test/issue-209/CMakeLists.txt b/test/issue-209/CMakeLists.txt
new file mode 100644
index 0000000..fa4c564
--- /dev/null
+++ b/test/issue-209/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_test_simple_schema(Issue::209
+ ${CMAKE_CURRENT_SOURCE_DIR}/entities.schema.json
+ ${CMAKE_CURRENT_SOURCE_DIR}/instance.json)
diff --git a/test/issue-209/color.schema.json b/test/issue-209/color.schema.json
new file mode 100644
index 0000000..2d4227b
--- /dev/null
+++ b/test/issue-209/color.schema.json
@@ -0,0 +1,8 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://example.invalid/color.schema.json",
+ "title": "color",
+ "description": "X11/HTML/CSS color name as a JSON string",
+ "type": "string",
+ "enum": [ "White", "Black", "Red" ]
+}
diff --git a/test/issue-209/entities.schema.json b/test/issue-209/entities.schema.json
new file mode 100644
index 0000000..95828b8
--- /dev/null
+++ b/test/issue-209/entities.schema.json
@@ -0,0 +1,16 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://example.invalid/entities.schema.json",
+ "title": "Entities",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "required": [ "name" ],
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "fg": { "$ref": "color.schema.json", "default": "Black" }
+ }
+ }
+}
diff --git a/test/issue-209/instance.json b/test/issue-209/instance.json
new file mode 100644
index 0000000..8de2c32
--- /dev/null
+++ b/test/issue-209/instance.json
@@ -0,0 +1,10 @@
+[
+ {
+ "name": "player",
+ "fg": "White"
+ },
+ {
+ "name": "enemy",
+ "fg": "Red"
+ }
+]