From f78c4c026fd71341134c3c3d499e55387b7f143a Mon Sep 17 00:00:00 2001 From: doufu3344 Date: Tue, 11 Oct 2022 14:07:43 +0800 Subject: [PATCH] Added support for specifying floating value's format on serializing DTO to JSON The program does not check the format, you need to make sure it is right. demo: class MyDto : public DTO { DTO_INIT(MyDto, DTO) DTO_FIELD_INFO(value) { info->format = "%.2f"; } DTO_FIELD(Float64, value); }; --- src/oatpp/core/data/mapping/type/Object.hpp | 4 + src/oatpp/core/data/stream/Stream.cpp | 4 +- src/oatpp/core/data/stream/Stream.hpp | 1 + src/oatpp/parser/json/mapping/Serializer.cpp | 9 ++ src/oatpp/parser/json/mapping/Serializer.hpp | 5 + test/CMakeLists.txt | 2 + test/oatpp/AllTestsMain.cpp | 3 + test/oatpp/parser/json/mapping/FloatTest.cpp | 123 +++++++++++++++++++ test/oatpp/parser/json/mapping/FloatTest.hpp | 42 +++++++ 9 files changed, 191 insertions(+), 2 deletions(-) create mode 100644 test/oatpp/parser/json/mapping/FloatTest.cpp create mode 100644 test/oatpp/parser/json/mapping/FloatTest.hpp diff --git a/src/oatpp/core/data/mapping/type/Object.hpp b/src/oatpp/core/data/mapping/type/Object.hpp index 9c277801..6aae76f9 100644 --- a/src/oatpp/core/data/mapping/type/Object.hpp +++ b/src/oatpp/core/data/mapping/type/Object.hpp @@ -102,6 +102,10 @@ public: */ std::string pattern = ""; + /** + * Format. + */ + std::string format = OATPP_FLOAT_STRING_FORMAT; /** * Required. */ diff --git a/src/oatpp/core/data/stream/Stream.cpp b/src/oatpp/core/data/stream/Stream.cpp index 7a2013e2..180b00c3 100644 --- a/src/oatpp/core/data/stream/Stream.cpp +++ b/src/oatpp/core/data/stream/Stream.cpp @@ -399,7 +399,7 @@ v_io_size ConsistentOutputStream::writeAsString(v_uint64 value){ v_io_size ConsistentOutputStream::writeAsString(v_float32 value){ v_char8 a[100]; - auto size = utils::conversion::float32ToCharSequence(value, &a[0], 100); + auto size = utils::conversion::float32ToCharSequence(value, &a[0], 100, floatFormat->c_str()); if(size > 0){ return writeSimple(&a[0], size); } @@ -408,7 +408,7 @@ v_io_size ConsistentOutputStream::writeAsString(v_float32 value){ v_io_size ConsistentOutputStream::writeAsString(v_float64 value){ v_char8 a[100]; - auto size = utils::conversion::float64ToCharSequence(value, &a[0], 100); + auto size = utils::conversion::float64ToCharSequence(value, &a[0], 100, floatFormat->c_str()); if(size > 0){ return writeSimple(&a[0], size); } diff --git a/src/oatpp/core/data/stream/Stream.hpp b/src/oatpp/core/data/stream/Stream.hpp index 2f5fdf08..a7068205 100644 --- a/src/oatpp/core/data/stream/Stream.hpp +++ b/src/oatpp/core/data/stream/Stream.hpp @@ -405,6 +405,7 @@ public: */ class ConsistentOutputStream : public OutputStream { public: + String floatFormat = OATPP_FLOAT_STRING_FORMAT; /** * Convert value to string and write to stream. diff --git a/src/oatpp/parser/json/mapping/Serializer.cpp b/src/oatpp/parser/json/mapping/Serializer.cpp index 97589a77..b9ce8cb1 100644 --- a/src/oatpp/parser/json/mapping/Serializer.cpp +++ b/src/oatpp/parser/json/mapping/Serializer.cpp @@ -243,7 +243,14 @@ void Serializer::serializeObject(Serializer* serializer, (first) ? first = false : stream->writeSimple(",", 1); serializeString(stream, field->name, std::strlen(field->name), serializer->m_config->escapeFlags); stream->writeSimple(":", 1); + auto streamFloatFormat = stream->floatFormat; + if (stream->floatFormat != field->info.format) { + streamFloatFormat = stream->floatFormat; + stream->floatFormat = field->info.format; + } serializer->serialize(stream, value); + if (stream->floatFormat != streamFloatFormat) + stream->floatFormat = streamFloatFormat; } } @@ -276,6 +283,8 @@ void Serializer::serialize(data::stream::ConsistentOutputStream* stream, void Serializer::serializeToStream(data::stream::ConsistentOutputStream* stream, const oatpp::Void& polymorph) { + if(m_config->floatStringFormat != stream->floatFormat) + stream->floatFormat = m_config->floatStringFormat; if(m_config->useBeautifier) { json::Beautifier beautifier(stream, " ", "\n"); serialize(&beautifier, polymorph); diff --git a/src/oatpp/parser/json/mapping/Serializer.hpp b/src/oatpp/parser/json/mapping/Serializer.hpp index 6795cb4e..db531dd5 100644 --- a/src/oatpp/parser/json/mapping/Serializer.hpp +++ b/src/oatpp/parser/json/mapping/Serializer.hpp @@ -113,6 +113,11 @@ public: */ v_uint32 escapeFlags = json::Utils::FLAG_ESCAPE_ALL; + /** + * Format of float string. + */ + oatpp::String floatStringFormat = OATPP_FLOAT_STRING_FORMAT; + }; public: typedef void (*SerializerMethod)(Serializer*, diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ee3c999e..07934c6b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -75,6 +75,8 @@ add_executable(oatppAllTests oatpp/parser/json/mapping/DeserializerTest.hpp oatpp/parser/json/mapping/EnumTest.cpp oatpp/parser/json/mapping/EnumTest.hpp + oatpp/parser/json/mapping/FloatTest.cpp + oatpp/parser/json/mapping/FloatTest.hpp oatpp/parser/json/mapping/UnorderedSetTest.cpp oatpp/parser/json/mapping/UnorderedSetTest.hpp oatpp/web/protocol/http/encoding/ChunkedTest.cpp diff --git a/test/oatpp/AllTestsMain.cpp b/test/oatpp/AllTestsMain.cpp index c315451d..4f075e29 100644 --- a/test/oatpp/AllTestsMain.cpp +++ b/test/oatpp/AllTestsMain.cpp @@ -22,6 +22,7 @@ #include "oatpp/parser/json/mapping/DTOMapperPerfTest.hpp" #include "oatpp/parser/json/mapping/DTOMapperTest.hpp" #include "oatpp/parser/json/mapping/EnumTest.hpp" +#include "oatpp/parser/json/mapping/FloatTest.hpp" #include "oatpp/parser/json/mapping/UnorderedSetTest.hpp" #include "oatpp/encoding/UnicodeTest.hpp" @@ -123,6 +124,8 @@ void runTests() { OATPP_RUN_TEST(oatpp::test::parser::json::mapping::EnumTest); + OATPP_RUN_TEST(oatpp::test::parser::json::mapping::FloatTest); + OATPP_RUN_TEST(oatpp::test::parser::json::mapping::UnorderedSetTest); OATPP_RUN_TEST(oatpp::test::parser::json::mapping::DeserializerTest); diff --git a/test/oatpp/parser/json/mapping/FloatTest.cpp b/test/oatpp/parser/json/mapping/FloatTest.cpp new file mode 100644 index 00000000..d1f2c1ac --- /dev/null +++ b/test/oatpp/parser/json/mapping/FloatTest.cpp @@ -0,0 +1,123 @@ +/*************************************************************************** + * + * Project _____ __ ____ _ _ + * ( _ ) /__\ (_ _)_| |_ _| |_ + * )(_)( /(__)\ )( (_ _)(_ _) + * (_____)(__)(__)(__) |_| |_| + * + * + * Copyright 2018-present, Leonid Stryzhevskyi + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ***************************************************************************/ + +#include "FloatTest.hpp" + +#include "oatpp/parser/json/mapping/ObjectMapper.hpp" + +#include "oatpp/core/macro/codegen.hpp" + +namespace oatpp { namespace test { namespace parser { namespace json { namespace mapping { + +namespace { + +#include OATPP_CODEGEN_BEGIN(DTO) + + +class DTO_32_0 : public oatpp::DTO { + + DTO_INIT(DTO_32_0, DTO) + + DTO_FIELD(Float32, f32); +}; + +class DTO_32_1 : public oatpp::DTO { + + DTO_INIT(DTO_32_1, DTO) + + DTO_FIELD_INFO(f32) { + info->format = "%.2f"; + } + DTO_FIELD(Float32, f32); +}; + +class DTO_64_0 : public oatpp::DTO { + + DTO_INIT(DTO_64_0, DTO) + + DTO_FIELD(Float64, f64); +}; + +class DTO_64_1 : public oatpp::DTO { + + DTO_INIT(DTO_64_1, DTO) + + DTO_FIELD_INFO(f64) { + info->format = "%.2f"; + } + DTO_FIELD(Float64, f64); +}; + +#include OATPP_CODEGEN_END(DTO) + +} + +void FloatTest::onRun() { + + oatpp::parser::json::mapping::ObjectMapper mapper; + + OATPP_LOGI(TAG, "Serialize float: 123456.123456"); + { + auto test = DTO_32_0::createShared(); + test->f32 = 123456.123456; + OATPP_LOGI(TAG, "using default format..."); + auto json = mapper.writeToString(test); + OATPP_LOGD(TAG, "json='%s'", json->c_str()); + OATPP_ASSERT(json != "{\"f32\":123456.123456}"); + OATPP_LOGI(TAG, "OK"); + } + + { + auto test = DTO_32_1::createShared(); + test->f32 = 123456.123456; + OATPP_LOGI(TAG, "using \"%%.2f\" format..."); + auto json = mapper.writeToString(test); + OATPP_LOGD(TAG, "json='%s'", json->c_str()); + OATPP_ASSERT(json == "{\"f32\":123456.12}"); + OATPP_LOGI(TAG, "OK"); + } + + { + auto test = DTO_64_0::createShared(); + test->f64 = 123456.123456;// +0.2; + OATPP_LOGI(TAG, "using default format..."); + auto json = mapper.writeToString(test); + OATPP_LOGD(TAG, "json='%s'", json->c_str()); + OATPP_ASSERT(json == "{\"f64\":123456.123456}"); + OATPP_LOGI(TAG, "OK"); + } + + { + auto test = DTO_64_1::createShared(); + test->f64 = 123456.123456; + OATPP_LOGI(TAG, "using \"%%.2f\" format..."); + auto json = mapper.writeToString(test); + OATPP_LOGD(TAG, "json='%s'", json->c_str()); + OATPP_ASSERT(json == "{\"f64\":123456.12}"); + OATPP_LOGI(TAG, "OK"); + } + +} + +}}}}} \ No newline at end of file diff --git a/test/oatpp/parser/json/mapping/FloatTest.hpp b/test/oatpp/parser/json/mapping/FloatTest.hpp new file mode 100644 index 00000000..f2e67d0f --- /dev/null +++ b/test/oatpp/parser/json/mapping/FloatTest.hpp @@ -0,0 +1,42 @@ +/*************************************************************************** + * + * Project _____ __ ____ _ _ + * ( _ ) /__\ (_ _)_| |_ _| |_ + * )(_)( /(__)\ )( (_ _)(_ _) + * (_____)(__)(__)(__) |_| |_| + * + * + * Copyright 2018-present, Leonid Stryzhevskyi + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ***************************************************************************/ + +#ifndef oatpp_test_parser_json_mapping_FloatTest_hpp +#define oatpp_test_parser_json_mapping_FloatTest_hpp + +#include "oatpp-test/UnitTest.hpp" + +namespace oatpp { namespace test { namespace parser { namespace json { namespace mapping { + +class FloatTest : public UnitTest{ +public: + + FloatTest():UnitTest("TEST[parser::json::mapping::FloatTest]"){} + void onRun() override; + +}; + +}}}}} + +#endif /* oatpp_test_parser_json_mapping_FloatTest_hpp */