diff --git a/src/oatpp/parser/json/mapping/Deserializer.cpp b/src/oatpp/parser/json/mapping/Deserializer.cpp index 180625c3..073d7b12 100644 --- a/src/oatpp/parser/json/mapping/Deserializer.cpp +++ b/src/oatpp/parser/json/mapping/Deserializer.cpp @@ -447,7 +447,13 @@ oatpp::Void Deserializer::deserializeObject(Deserializer* deserializer, parser:: skipValue(caret); polymorphs.emplace_back(field, label.toString()); // store polymorphs for later processing. } else { - field->set(static_cast(object.get()), deserializer->deserialize(caret, field->type)); + auto value = deserializer->deserialize(caret, field->type); + if(field->info.required && value == nullptr) { + throw std::runtime_error("[oatpp::parser::json::mapping::Deserializer::deserialize()]: " + "Error. " + std::string(type->nameQualifier) + "::" + + std::string(field->name) + " is required!"); + } + field->set(static_cast(object.get()), value); } } else if (deserializer->getConfig()->allowUnknownFields) { @@ -479,6 +485,11 @@ oatpp::Void Deserializer::deserializeObject(Deserializer* deserializer, parser:: parser::Caret polyCaret(p.second); auto selectedType = p.first->info.typeSelector->selectType(static_cast(object.get())); auto value = deserializer->deserialize(polyCaret, selectedType); + if(p.first->info.required && value == nullptr) { + throw std::runtime_error("[oatpp::parser::json::mapping::Deserializer::deserialize()]: " + "Error. " + std::string(type->nameQualifier) + "::" + + std::string(p.first->name) + " is required!"); + } oatpp::Any any(value); p.first->set(static_cast(object.get()), oatpp::Void(any.getPtr(), p.first->type)); } diff --git a/test/oatpp/parser/json/mapping/DeserializerTest.cpp b/test/oatpp/parser/json/mapping/DeserializerTest.cpp index a2122500..feba43c8 100644 --- a/test/oatpp/parser/json/mapping/DeserializerTest.cpp +++ b/test/oatpp/parser/json/mapping/DeserializerTest.cpp @@ -79,6 +79,58 @@ class Test4 : public oatpp::DTO { }; +class Test5 : public oatpp::DTO { + + DTO_INIT(Test5, DTO) + + DTO_FIELD_INFO(strF) { + info->required = true; + } + DTO_FIELD(String, strF); +}; + +class Test6 : public oatpp::DTO { + + DTO_INIT(Test6, DTO) + + DTO_FIELD(String, strF); +}; + +class TestChild1 : public oatpp::DTO { + + DTO_INIT(TestChild1, DTO) + + DTO_FIELD_INFO(name) { + info->required = true; + } + DTO_FIELD(String, name); +}; + +class Test7 : public oatpp::DTO { + + DTO_INIT(Test7, DTO) + + DTO_FIELD(String, strF); + + DTO_FIELD(Object, child); +}; + +class TestChild2 : public oatpp::DTO { + + DTO_INIT(TestChild2, DTO) + + DTO_FIELD(String, name); +}; + +class Test8 : public oatpp::DTO { + + DTO_INIT(Test8, DTO) + + DTO_FIELD(String, strF); + + DTO_FIELD(Object, child); +}; + class AnyDto : public oatpp::DTO { DTO_INIT(AnyDto, DTO) @@ -100,7 +152,7 @@ void DeserializerTest::onRun(){ OATPP_ASSERT(obj1) OATPP_ASSERT(!obj1->strF) - obj1 = mapper->readFromString>("{\"strF\":\"value1\"}"); + obj1 = mapper->readFromString>(R"({"strF":"value1"})"); OATPP_ASSERT(obj1) OATPP_ASSERT(obj1->strF) @@ -185,6 +237,34 @@ void DeserializerTest::onRun(){ OATPP_ASSERT(obj4->list->size() == 0) OATPP_ASSERT(obj4->map->size() == 0) + data::mapping::type::DTOWrapper obj5; + try { + obj5 = mapper->readFromString>(R"({"strF":null})"); + } catch (std::runtime_error& e) { + OATPP_LOGD(TAG, "Test5::strF is required!") + } + OATPP_ASSERT(obj5 == nullptr) + + try { + auto obj6 = mapper->readFromString>(R"({"strF":null})"); + } catch (std::runtime_error& e) { + OATPP_ASSERT(false) + } + + data::mapping::type::DTOWrapper obj7; + try { + obj7 = mapper->readFromString>(R"({"strF":"value1", "child":{"name":null}})"); + } catch (std::runtime_error& e) { + OATPP_LOGD(TAG, "TestChild1::name is required!") + } + OATPP_ASSERT(obj7 == nullptr) + + try { + auto obj8 = mapper->readFromString>(R"({"strF":"value1", "child":{"name":null}})"); + } catch (std::runtime_error& e) { + OATPP_ASSERT(false) + } + OATPP_LOGD(TAG, "Any: String") { auto dto = mapper->readFromString>(R"({"any":"my_string"})");