diff --git a/src/oatpp/parser/json/mapping/Serializer.cpp b/src/oatpp/parser/json/mapping/Serializer.cpp index fc469a59..7040efa3 100644 --- a/src/oatpp/parser/json/mapping/Serializer.cpp +++ b/src/oatpp/parser/json/mapping/Serializer.cpp @@ -64,7 +64,6 @@ Serializer::Serializer(const std::shared_ptr& config) setSerializerMethod(data::mapping::type::__class::AbstractPairList::CLASS_ID, &Serializer::serializeMap); setSerializerMethod(data::mapping::type::__class::AbstractUnorderedMap::CLASS_ID, &Serializer::serializeMap); - m_context = std::unique_ptr(new Context()); } void Serializer::setSerializerMethod(const data::mapping::type::ClassId& classId, SerializerMethod method) { @@ -76,42 +75,40 @@ void Serializer::setSerializerMethod(const data::mapping::type::ClassId& classId } template<> -void Serializer::serializePrimitive(Serializer* serializer, - data::stream::ConsistentOutputStream* stream, +void Serializer::serializePrimitive(const std::unique_ptr& context, const oatpp::Void& polymorph){ if (polymorph) { std::string format; - if (!serializer->m_context->info.format.empty()) { - format = serializer->m_context->info.format; + if (!context->info.format.empty()) { + format = context->info.format; } - else if (!serializer->m_config->floatStringFormat->empty()) { - format = serializer->m_config->floatStringFormat; + else if (!context->serializer->m_config->floatStringFormat->empty()) { + format = context->serializer->m_config->floatStringFormat; } - stream->writeAsString(*static_cast(polymorph.get()), + context->stream->writeAsString(*static_cast(polymorph.get()), format.c_str()); } else { - stream->writeSimple("null", 4); + context->stream->writeSimple("null", 4); } } template<> -void Serializer::serializePrimitive(Serializer* serializer, - data::stream::ConsistentOutputStream* stream, +void Serializer::serializePrimitive(const std::unique_ptr& context, const oatpp::Void& polymorph) { if (polymorph) { std::string format; - if (!serializer->m_context->info.format.empty()) { - format = serializer->m_context->info.format; + if (!context->info.format.empty()) { + format = context->info.format; } - else if (!serializer->m_config->floatStringFormat->empty()) { - format = serializer->m_config->floatStringFormat; + else if (!context->serializer->m_config->floatStringFormat->empty()) { + format = context->serializer->m_config->floatStringFormat; } - stream->writeAsString(*static_cast(polymorph.get()), + context->stream->writeAsString(*static_cast(polymorph.get()), format.c_str()); } else { - stream->writeSimple("null", 4); + context->stream->writeSimple("null", 4); } } @@ -122,39 +119,36 @@ void Serializer::serializeString(data::stream::ConsistentOutputStream* stream, c stream->writeCharSimple('\"'); } -void Serializer::serializeString(Serializer* serializer, - data::stream::ConsistentOutputStream* stream, +void Serializer::serializeString(const std::unique_ptr& context, const oatpp::Void& polymorph) { if(!polymorph) { - stream->writeSimple("null", 4); + context->stream->writeSimple("null", 4); return; } auto str = static_cast(polymorph.get()); - serializeString(stream, str->data(), str->size(), serializer->m_config->escapeFlags); + serializeString(context->stream, str->data(), str->size(), context->serializer->m_config->escapeFlags); } -void Serializer::serializeAny(Serializer* serializer, - data::stream::ConsistentOutputStream* stream, +void Serializer::serializeAny(const std::unique_ptr& context, const oatpp::Void& polymorph) { if(!polymorph) { - stream->writeSimple("null", 4); + context->stream->writeSimple("null", 4); return; } auto anyHandle = static_cast(polymorph.get()); - serializer->serialize(stream, oatpp::Void(anyHandle->ptr, anyHandle->type)); + context->serializer->serialize(context, oatpp::Void(anyHandle->ptr, anyHandle->type)); } -void Serializer::serializeEnum(Serializer* serializer, - data::stream::ConsistentOutputStream* stream, +void Serializer::serializeEnum(const std::unique_ptr& context, const oatpp::Void& polymorph) { auto polymorphicDispatcher = static_cast( @@ -162,7 +156,7 @@ void Serializer::serializeEnum(Serializer* serializer, ); data::mapping::type::EnumInterpreterError e = data::mapping::type::EnumInterpreterError::OK; - serializer->serialize(stream, polymorphicDispatcher->toInterpretation(polymorph, e)); + context->serializer->serialize(context, polymorphicDispatcher->toInterpretation(polymorph, e)); if(e == data::mapping::type::EnumInterpreterError::OK) { return; @@ -177,13 +171,12 @@ void Serializer::serializeEnum(Serializer* serializer, } -void Serializer::serializeCollection(Serializer* serializer, - data::stream::ConsistentOutputStream* stream, +void Serializer::serializeCollection(const std::unique_ptr& context, const oatpp::Void& polymorph) { if(!polymorph) { - stream->writeSimple("null", 4); + context->stream->writeSimple("null", 4); return; } @@ -191,31 +184,32 @@ void Serializer::serializeCollection(Serializer* serializer, polymorph.getValueType()->polymorphicDispatcher ); - stream->writeCharSimple('['); + context->stream->writeCharSimple('['); bool first = true; auto iterator = dispatcher->beginIteration(polymorph); while (!iterator->finished()) { const auto& value = iterator->get(); - if(value || serializer->getConfig()->includeNullFields || serializer->getConfig()->alwaysIncludeNullCollectionElements) { - (first) ? first = false : stream->writeSimple(",", 1); - serializer->serialize(stream, value); + if(value || + context->serializer->getConfig()->includeNullFields || + context->serializer->getConfig()->alwaysIncludeNullCollectionElements) { + (first) ? first = false : context->stream->writeSimple(",", 1); + context->serializer->serialize(context, value); } iterator->next(); } - stream->writeCharSimple(']'); + context->stream->writeCharSimple(']'); } -void Serializer::serializeMap(Serializer* serializer, - data::stream::ConsistentOutputStream* stream, +void Serializer::serializeMap(const std::unique_ptr& context, const oatpp::Void& polymorph) { if(!polymorph) { - stream->writeSimple("null", 4); + context->stream->writeSimple("null", 4); return; } @@ -228,39 +222,40 @@ void Serializer::serializeMap(Serializer* serializer, throw std::runtime_error("[oatpp::parser::json::mapping::Serializer::serializeMap()]: Invalid json map key. Key should be String"); } - stream->writeCharSimple('{'); + context->stream->writeCharSimple('{'); bool first = true; auto iterator = dispatcher->beginIteration(polymorph); while (!iterator->finished()) { const auto& value = iterator->getValue(); - if(value || serializer->m_config->includeNullFields || serializer->m_config->alwaysIncludeNullCollectionElements) { - (first) ? first = false : stream->writeSimple(",", 1); + if(value || + context->serializer->m_config->includeNullFields || + context->serializer->m_config->alwaysIncludeNullCollectionElements) { + (first) ? first = false : context->stream->writeSimple(",", 1); const auto& untypedKey = iterator->getKey(); const auto& key = oatpp::String(std::static_pointer_cast(untypedKey.getPtr())); - serializeString(stream, key->data(), key->size(), serializer->m_config->escapeFlags); - stream->writeSimple(":", 1); - serializer->serialize(stream, value); + serializeString(context->stream, key->data(), key->size(), context->serializer->m_config->escapeFlags); + context->stream->writeSimple(":", 1); + context->serializer->serialize(context, value); } iterator->next(); } - stream->writeCharSimple('}'); + context->stream->writeCharSimple('}'); } -void Serializer::serializeObject(Serializer* serializer, - data::stream::ConsistentOutputStream* stream, - const oatpp::Void& polymorph) +void Serializer::serializeObject(const std::unique_ptr& context, + const oatpp::Void& polymorph) { if(!polymorph) { - stream->writeSimple("null", 4); + context->stream->writeSimple("null", 4); return; } - stream->writeCharSimple('{'); + context->stream->writeCharSimple('{'); bool first = true; auto dispatcher = static_cast( @@ -268,8 +263,7 @@ void Serializer::serializeObject(Serializer* serializer, ); auto fields = dispatcher->getProperties()->getList(); auto object = static_cast(polymorph.get()); - auto config = serializer->m_config; - auto &context = serializer->m_context; + auto config = context->serializer->m_config; for (auto const& field : fields) { @@ -282,32 +276,31 @@ void Serializer::serializeObject(Serializer* serializer, } if (value || config->includeNullFields || (field->info.required && config->alwaysIncludeRequired)) { - (first) ? first = false : stream->writeSimple(",", 1); - serializeString(stream, field->name, std::strlen(field->name), serializer->m_config->escapeFlags); - stream->writeSimple(":", 1); - + (first) ? first = false : context->stream->writeSimple(",", 1); + serializeString(context->stream, field->name, std::strlen(field->name), context->serializer->m_config->escapeFlags); + context->stream->writeSimple(":", 1); context->info = field->info; - serializer->serialize(stream, value); + context->serializer->serialize(context, value); } } - stream->writeCharSimple('}'); + context->stream->writeCharSimple('}'); } -void Serializer::serialize(data::stream::ConsistentOutputStream* stream, +void Serializer::serialize(const std::unique_ptr& context, const oatpp::Void& polymorph) { auto id = polymorph.getValueType()->classId.id; auto& method = m_methods[id]; if(method) { - (*method)(this, stream, polymorph); + (*method)(context, polymorph); } else { auto* interpretation = polymorph.getValueType()->findInterpretation(m_config->enabledInterpretations); if(interpretation) { - serialize(stream, interpretation->toInterpretation(polymorph)); + serialize(context, interpretation->toInterpretation(polymorph)); } else { throw std::runtime_error("[oatpp::parser::json::mapping::Serializer::serialize()]: " "Error. No serialize method for type '" + @@ -322,9 +315,11 @@ void Serializer::serializeToStream(data::stream::ConsistentOutputStream* stream, { if(m_config->useBeautifier) { json::Beautifier beautifier(stream, " ", "\n"); - serialize(&beautifier, polymorph); + auto context = std::unique_ptr(new Context(this, &beautifier)); + serialize(context, polymorph); } else { - serialize(stream, polymorph); + auto context = std::unique_ptr(new Context(this,stream)); + serialize(context, polymorph); } } diff --git a/src/oatpp/parser/json/mapping/Serializer.hpp b/src/oatpp/parser/json/mapping/Serializer.hpp index b40bef74..78e514fc 100644 --- a/src/oatpp/parser/json/mapping/Serializer.hpp +++ b/src/oatpp/parser/json/mapping/Serializer.hpp @@ -129,29 +129,29 @@ private: /** * Constructor. */ - Context() + Context(Serializer *serializer, data::stream::ConsistentOutputStream* stream) + : serializer(serializer), stream(stream) {} public: + Serializer* serializer; + data::stream::ConsistentOutputStream* stream; + data::mapping::type::BaseObject::Property::Info info; }; public: - typedef void (*SerializerMethod)(Serializer*, - data::stream::ConsistentOutputStream*, + typedef void (*SerializerMethod)(const std::unique_ptr&, const oatpp::Void&); private: template - static void serializePrimitive(Serializer* serializer, - data::stream::ConsistentOutputStream* stream, + static void serializePrimitive(const std::unique_ptr& context, const oatpp::Void& polymorph){ - (void) serializer; - if(polymorph){ - stream->writeAsString(* static_cast(polymorph.get())); + context->stream->writeAsString(* static_cast(polymorph.get())); } else { - stream->writeSimple("null", 4); + context->stream->writeSimple("null", 4); } } @@ -160,35 +160,28 @@ private: v_buff_size size, v_uint32 escapeFlags); - static void serializeString(Serializer* serializer, - data::stream::ConsistentOutputStream* stream, + static void serializeString(const std::unique_ptr& context, const oatpp::Void& polymorph); - static void serializeAny(Serializer* serializer, - data::stream::ConsistentOutputStream* stream, + static void serializeAny(const std::unique_ptr& context, const oatpp::Void& polymorph); - static void serializeEnum(Serializer* serializer, - data::stream::ConsistentOutputStream* stream, + static void serializeEnum(const std::unique_ptr& context, const oatpp::Void& polymorph); - static void serializeCollection(Serializer* serializer, - data::stream::ConsistentOutputStream* stream, + static void serializeCollection(const std::unique_ptr& context, const oatpp::Void& polymorph); - static void serializeMap(Serializer* serializer, - data::stream::ConsistentOutputStream* stream, + static void serializeMap(const std::unique_ptr& context, const oatpp::Void& polymorph); - static void serializeObject(Serializer* serializer, - data::stream::ConsistentOutputStream* stream, + static void serializeObject(const std::unique_ptr& context, const oatpp::Void& polymorph); - void serialize(data::stream::ConsistentOutputStream* stream, const oatpp::Void& polymorph); + void serialize(const std::unique_ptr& context, const oatpp::Void& polymorph); private: std::shared_ptr m_config; - std::unique_ptr m_context; std::vector m_methods; public: @@ -221,14 +214,12 @@ public: }; template<> -void Serializer::serializePrimitive(Serializer* serializer, - data::stream::ConsistentOutputStream* stream, - const oatpp::Void& polymorph); +void Serializer::serializePrimitive(const std::unique_ptr& context, + const oatpp::Void& polymorph); template<> -void Serializer::serializePrimitive(Serializer* serializer, - data::stream::ConsistentOutputStream* stream, - const oatpp::Void& polymorph); +void Serializer::serializePrimitive(const std::unique_ptr& context, + const oatpp::Void& polymorph); }}}} diff --git a/test/oatpp/parser/json/mapping/FloatTest.cpp b/test/oatpp/parser/json/mapping/FloatTest.cpp index 2230c7b3..4b4af6a6 100644 --- a/test/oatpp/parser/json/mapping/FloatTest.cpp +++ b/test/oatpp/parser/json/mapping/FloatTest.cpp @@ -22,6 +22,8 @@ * ***************************************************************************/ +#include + #include "FloatTest.hpp" #include "oatpp/parser/json/mapping/ObjectMapper.hpp" @@ -179,6 +181,56 @@ void FloatTest::onRun() { OATPP_LOGI(TAG, "OK"); } + { + mapperFmt.getSerializer()->getConfig()->useBeautifier = true; + auto test = DTO_64_0::createShared(); + test->f64 = 123456.123456; + OATPP_LOGI(TAG, "using config's \"%%.1f\" format(useBeautifier) ..."); + auto json = mapperFmt.writeToString(test); + OATPP_LOGD(TAG, "json='%s'", json->c_str()); + OATPP_ASSERT(json == "{\n \"f64\": 123456.1\n}"); + OATPP_LOGI(TAG, "OK"); + } + + { + int count = 10000; + bool parallel_result = true; + auto test1 = DTO_64_0::createShared(); + test1->f64 = 123456.123456; + OATPP_LOGI(TAG, "parallel 1: using default format..."); + OATPP_LOGI(TAG, "expect: json1='%s'", "{\"f64\":123456.123456}"); + std::thread proc1([&]() { + for (int i = 0; i < count; ++i) { + auto json = mapper.writeToString(test1); + if (json != "{\"f64\":123456.123456}") { + OATPP_LOGE(TAG, "json1='%s'", json->c_str()); + parallel_result = false; + break; + } + } + }); + + auto test2 = DTO_64_1::createShared(); + test2->f64 = 123456.123456; + OATPP_LOGI(TAG, "parallel 2: using \"%%.2f\" format..."); + OATPP_LOGI(TAG, "expect: json2='%s'", "{\"f64\":123456.12}"); + std::thread proc2([&]() { + for (int i = 0; i < count; ++i) { + auto json = mapper.writeToString(test2); + if (json != "{\"f64\":123456.12}") { + OATPP_LOGE(TAG, "json2='%s'", json->c_str()); + parallel_result = false; + break; + } + } + }); + proc1.join(); + proc2.join(); + + OATPP_ASSERT(parallel_result == true); + OATPP_LOGI(TAG, "parallel OK"); + } + } -}}}}} \ No newline at end of file +}}}}}