3535#include " rapidjson/writer.h"
3636
3737namespace paimon {
38+
3839class RapidJsonUtil {
3940 public:
4041 RapidJsonUtil () = delete ;
4142 ~RapidJsonUtil () = delete ;
4243
43- // supports vector and map and optional, if T is custom type, T must have ToJson()
44- // noted that rapidjson does not support map with non string key (will
45- // trigger assert in rapidjson: Assertion `name.IsString()' failed)
46- // therefore, RapidJsonUtil convert key to string in serialize and convert string to key type in
47- // deserialize
44+ // if T is custom type, T must have ToJson()
4845 template <typename T>
4946 static inline Status ToJsonString (const T& obj, std::string* json_str) {
5047 rapidjson::Document doc;
@@ -53,6 +50,9 @@ class RapidJsonUtil {
5350 try {
5451 if constexpr (is_pointer<T>::value) {
5552 value = obj->ToJson (&allocator);
53+ } else if constexpr (std::is_same_v<T, std::map<std::string, std::string>>) {
54+ *json_str = MapToJsonString (obj);
55+ return Status::OK ();
5656 } else {
5757 value = obj.ToJson (&allocator);
5858 }
@@ -67,19 +67,27 @@ class RapidJsonUtil {
6767 return Status::OK ();
6868 }
6969
70- // supports vector and map, if T is custom type, T must have FromJson()
70+ // if T is custom type, T must have FromJson()
7171 template <typename T>
7272 static inline Status FromJsonString (const std::string& json_str, T* obj) {
73- rapidjson::Document doc;
74- if (!obj || !FromJson (json_str, &doc)) {
75- return Status::Invalid (" deserialize failed: " , json_str);
73+ if (!obj) {
74+ return Status::Invalid (" deserialize failed: obj is nullptr" );
7675 }
77- try {
78- obj->FromJson (doc);
79- } catch (const std::invalid_argument& e) {
80- return Status::Invalid (" deserialize failed, possibly type incompatible: " , e.what ());
81- } catch (...) {
82- return Status::Invalid (" deserialize failed, reason unknown: " , json_str);
76+ if constexpr (std::is_same_v<T, std::map<std::string, std::string>>) {
77+ PAIMON_ASSIGN_OR_RAISE (*obj, MapFromJsonString (json_str));
78+ } else {
79+ rapidjson::Document doc;
80+ if (!FromJson (json_str, &doc)) {
81+ return Status::Invalid (" deserialize failed: " , json_str);
82+ }
83+ try {
84+ obj->FromJson (doc);
85+ } catch (const std::invalid_argument& e) {
86+ return Status::Invalid (" deserialize failed, possibly type incompatible: " ,
87+ e.what ());
88+ } catch (...) {
89+ return Status::Invalid (" deserialize failed, reason unknown: " , json_str);
90+ }
8391 }
8492 return Status::OK ();
8593 }
@@ -140,6 +148,42 @@ class RapidJsonUtil {
140148
141149 template <typename T>
142150 static T GetValue (const rapidjson::Value& value);
151+
152+ static std::string MapToJsonString (const std::map<std::string, std::string>& map) {
153+ rapidjson::Document d;
154+ d.SetObject ();
155+ rapidjson::Document::AllocatorType& allocator = d.GetAllocator ();
156+
157+ for (const auto & kv : map) {
158+ d.AddMember (rapidjson::Value (kv.first .c_str (), allocator),
159+ rapidjson::Value (kv.second .c_str (), allocator), allocator);
160+ }
161+
162+ rapidjson::StringBuffer buffer;
163+ rapidjson::Writer<rapidjson::StringBuffer> writer (buffer);
164+ d.Accept (writer);
165+
166+ return buffer.GetString ();
167+ }
168+ static Result<std::map<std::string, std::string>> MapFromJsonString (
169+ const std::string& json_str) {
170+ rapidjson::Document doc;
171+ doc.Parse (json_str.c_str ());
172+ if (doc.HasParseError () || !doc.IsObject ()) {
173+ return Status::Invalid (" deserialize failed: parse error or not JSON object: " ,
174+ json_str);
175+ }
176+
177+ std::map<std::string, std::string> result;
178+ for (auto it = doc.MemberBegin (); it != doc.MemberEnd (); ++it) {
179+ if (!it->name .IsString () || !it->value .IsString ()) {
180+ return Status::Invalid (
181+ " deserialize failed: non-string key or value in JSON object: " , json_str);
182+ }
183+ result[it->name .GetString ()] = it->value .GetString ();
184+ }
185+ return result;
186+ }
143187};
144188
145189template <typename T>
0 commit comments