aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/protobuf/json
diff options
context:
space:
mode:
authordimastark <dimastark@yandex-team.com>2024-09-30 16:58:58 +0300
committerdimastark <dimastark@yandex-team.com>2024-09-30 17:11:11 +0300
commit4cd5d4661db60c7f096ec51f08bca0ed7aba8f9b (patch)
tree03a54adef9e505da807b2456aeadfc29a2b1ece6 /library/cpp/protobuf/json
parent334072c7351043236bdca34f2ede8ed1cb4a6d79 (diff)
downloadydb-4cd5d4661db60c7f096ec51f08bca0ed7aba8f9b.tar.gz
SortMapKeys in proto2json for deterministic seriarialization
commit_hash:e64dedae589fa2d16347be4d80e2596f46566b38
Diffstat (limited to 'library/cpp/protobuf/json')
-rw-r--r--library/cpp/protobuf/json/config.h8
-rw-r--r--library/cpp/protobuf/json/proto2json_printer.cpp19
-rw-r--r--library/cpp/protobuf/json/ut/proto2json_ut.cpp18
3 files changed, 43 insertions, 2 deletions
diff --git a/library/cpp/protobuf/json/config.h b/library/cpp/protobuf/json/config.h
index 98d484cdf4..d0d2d21bcf 100644
--- a/library/cpp/protobuf/json/config.h
+++ b/library/cpp/protobuf/json/config.h
@@ -109,6 +109,9 @@ namespace NProtobufJson {
bool WriteNanAsString = false;
+ // Sort keys in maps before serialization.
+ bool SortMapKeys = false;
+
TSelf& SetDoubleNDigits(ui32 ndigits) {
DoubleNDigits = ndigits;
return *this;
@@ -189,6 +192,11 @@ namespace NProtobufJson {
return *this;
}
+ TSelf& SetSortMapKeys(bool value) {
+ SortMapKeys = value;
+ return *this;
+ }
+
TSelf& SetStringifyNumbers(EStringifyNumbersMode stringify) {
StringifyNumbers = stringify;
return *this;
diff --git a/library/cpp/protobuf/json/proto2json_printer.cpp b/library/cpp/protobuf/json/proto2json_printer.cpp
index 5d0e140615..a9f8c3fce9 100644
--- a/library/cpp/protobuf/json/proto2json_printer.cpp
+++ b/library/cpp/protobuf/json/proto2json_printer.cpp
@@ -8,6 +8,7 @@
#include <library/cpp/protobuf/json/proto/enum_options.pb.h>
+#include <util/generic/map.h>
#include <util/generic/yexception.h>
#include <util/string/ascii.h>
#include <util/string/cast.h>
@@ -394,8 +395,22 @@ namespace NProtobufJson {
case FieldDescriptor::CPPTYPE_MESSAGE: {
if (isMap) {
- for (size_t i = 0, endI = reflection->FieldSize(proto, &field); i < endI; ++i) {
- PrintKeyValue(reflection->GetRepeatedMessage(proto, &field, i), json);
+ if (GetConfig().SortMapKeys) {
+ TMap<TString, size_t> keyToIndex;
+ for (size_t i = 0, endI = reflection->FieldSize(proto, &field); i < endI; ++i) {
+ const Message& fieldMessage = reflection->GetRepeatedMessage(proto, &field, i);
+ const FieldDescriptor* keyField = fieldMessage.GetDescriptor()->map_key();
+ Y_ABORT_UNLESS(keyField, "Map entry key field not found.");
+ TString key = MakeKey(fieldMessage, *keyField);
+ keyToIndex[key] = i;
+ }
+ for (const auto& [_, i] : keyToIndex) {
+ PrintKeyValue(reflection->GetRepeatedMessage(proto, &field, i), json);
+ }
+ } else {
+ for (size_t i = 0, endI = reflection->FieldSize(proto, &field); i < endI; ++i) {
+ PrintKeyValue(reflection->GetRepeatedMessage(proto, &field, i), json);
+ }
}
} else {
for (size_t i = 0, endI = reflection->FieldSize(proto, &field); i < endI; ++i) {
diff --git a/library/cpp/protobuf/json/ut/proto2json_ut.cpp b/library/cpp/protobuf/json/ut/proto2json_ut.cpp
index 9e98ab8a06..f5bcfac49d 100644
--- a/library/cpp/protobuf/json/ut/proto2json_ut.cpp
+++ b/library/cpp/protobuf/json/ut/proto2json_ut.cpp
@@ -997,6 +997,24 @@ Y_UNIT_TEST(TestMapUsingGeneratedAsJSON) {
UNIT_ASSERT_JSON_STRINGS_EQUAL(jsonStr.Str(), modelStr);
} // TestMapUsingGeneratedAsJSON
+Y_UNIT_TEST(TestMapSortedKeys) {
+ TMapType proto;
+
+ auto& items = *proto.MutableItems();
+ items["key1"] = "value1";
+ items["key2"] = "value2";
+ items["key3"] = "value3";
+
+ TString modelStr(R"_({"Items":{"key1":"value1","key2":"value2","key3":"value3"}})_");
+
+ TStringStream jsonStr;
+
+ auto config = TProto2JsonConfig().SetMapAsObject(true).SetSortMapKeys(false);
+ UNIT_ASSERT_NO_EXCEPTION(Proto2Json(proto, jsonStr, config));
+
+ UNIT_ASSERT_JSON_STRINGS_EQUAL(jsonStr.Str(), modelStr);
+} // TestMapSortedKeys
+
Y_UNIT_TEST(TestMapDefaultValue) {
TMapType proto;