json2proto.h 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. #pragma once
  2. #include "string_transform.h"
  3. #include "name_generator.h"
  4. #include <library/cpp/json/json_reader.h>
  5. #include <library/cpp/json/json_value.h>
  6. #include <util/stream/input.h>
  7. #include <util/stream/str.h>
  8. #include <util/stream/mem.h>
  9. namespace google {
  10. namespace protobuf {
  11. class Message;
  12. }
  13. }
  14. namespace NProtobufJson {
  15. struct TJson2ProtoConfig {
  16. using TSelf = TJson2ProtoConfig;
  17. using TValueVectorizer = std::function<NJson::TJsonValue::TArray(const NJson::TJsonValue& jsonValue)>;
  18. enum FldNameMode {
  19. FieldNameOriginalCase = 0, // default
  20. FieldNameLowerCase,
  21. FieldNameUpperCase,
  22. FieldNameCamelCase,
  23. FieldNameSnakeCase, // ABC -> a_b_c, UserID -> user_i_d
  24. FieldNameSnakeCaseDense // ABC -> abc, UserID -> user_id
  25. };
  26. enum EnumValueMode {
  27. EnumCaseSensetive = 0, // default
  28. EnumCaseInsensetive,
  29. EnumSnakeCaseInsensitive
  30. };
  31. TSelf& SetFieldNameMode(FldNameMode mode) {
  32. Y_ENSURE(mode == FieldNameOriginalCase || !UseJsonName, "FieldNameMode and UseJsonName are mutually exclusive");
  33. FieldNameMode = mode;
  34. return *this;
  35. }
  36. TSelf& SetUseJsonName(bool jsonName) {
  37. Y_ENSURE(!jsonName || FieldNameMode == FieldNameOriginalCase, "FieldNameMode and UseJsonName are mutually exclusive");
  38. UseJsonName = jsonName;
  39. return *this;
  40. }
  41. TSelf& AddStringTransform(TStringTransformPtr transform) {
  42. StringTransforms.push_back(transform);
  43. return *this;
  44. }
  45. TSelf& SetCastFromString(bool cast) {
  46. CastFromString = cast;
  47. return *this;
  48. }
  49. TSelf& SetDoNotCastEmptyStrings(bool cast) {
  50. DoNotCastEmptyStrings = cast;
  51. return *this;
  52. }
  53. TSelf& SetCastRobust(bool cast) {
  54. CastRobust = cast;
  55. return *this;
  56. }
  57. TSelf& SetMapAsObject(bool mapAsObject) {
  58. MapAsObject = mapAsObject;
  59. return *this;
  60. }
  61. TSelf& SetReplaceRepeatedFields(bool replaceRepeatedFields) {
  62. ReplaceRepeatedFields = replaceRepeatedFields;
  63. return *this;
  64. }
  65. TSelf& SetNameGenerator(TNameGenerator callback) {
  66. NameGenerator = callback;
  67. return *this;
  68. }
  69. TSelf& SetEnumValueMode(EnumValueMode enumValueMode) {
  70. EnumValueMode = enumValueMode;
  71. return *this;
  72. }
  73. TSelf& SetVectorizeScalars(bool vectorizeScalars) {
  74. VectorizeScalars = vectorizeScalars;
  75. return *this;
  76. }
  77. TSelf& SetAllowComments(bool value) {
  78. AllowComments = value;
  79. return *this;
  80. }
  81. TSelf& SetAllowUnknownFields(bool value) {
  82. AllowUnknownFields = value;
  83. return *this;
  84. }
  85. FldNameMode FieldNameMode = FieldNameOriginalCase;
  86. bool AllowUnknownFields = true;
  87. /// Use 'json_name' protobuf option for field name, mutually exclusive
  88. /// with FieldNameMode.
  89. bool UseJsonName = false;
  90. /// Transforms will be applied only to string values (== protobuf fields of string / bytes type).
  91. TVector<TStringTransformPtr> StringTransforms;
  92. /// Cast string json values to protobuf field type
  93. bool CastFromString = false;
  94. /// Skip empty strings, instead casting from string into scalar types.
  95. /// I.e. empty string like default value for scalar types.
  96. bool DoNotCastEmptyStrings = false;
  97. /// Cast all json values to protobuf field types
  98. bool CastRobust = false;
  99. /// Consider map to be an object, otherwise consider it to be an array of key/value objects
  100. bool MapAsObject = false;
  101. /// Throw exception if there is no required fields in json object.
  102. bool CheckRequiredFields = true;
  103. /// Replace repeated fields content during merging
  104. bool ReplaceRepeatedFields = false;
  105. /// Custom field names generator.
  106. TNameGenerator NameGenerator = {};
  107. /// Enum value parsing mode.
  108. EnumValueMode EnumValueMode = EnumCaseSensetive;
  109. /// Append scalars to repeated fields
  110. bool VectorizeScalars = false;
  111. /// Custom spliter non array value to repeated fields.
  112. TValueVectorizer ValueVectorizer;
  113. /// Allow js-style comments (both // and /**/)
  114. bool AllowComments = false;
  115. };
  116. /// @throw yexception
  117. void MergeJson2Proto(const NJson::TJsonValue& json, google::protobuf::Message& proto,
  118. const TJson2ProtoConfig& config = TJson2ProtoConfig());
  119. /// @throw yexception
  120. void MergeJson2Proto(const TStringBuf& json, google::protobuf::Message& proto,
  121. const TJson2ProtoConfig& config = TJson2ProtoConfig());
  122. /// @throw yexception
  123. inline void MergeJson2Proto(const TString& json, google::protobuf::Message& proto,
  124. const TJson2ProtoConfig& config = TJson2ProtoConfig()) {
  125. MergeJson2Proto(TStringBuf(json), proto, config);
  126. }
  127. /// @throw yexception
  128. void Json2Proto(const NJson::TJsonValue& json, google::protobuf::Message& proto,
  129. const TJson2ProtoConfig& config = TJson2ProtoConfig());
  130. /// @throw yexception
  131. void Json2Proto(const TStringBuf& json, google::protobuf::Message& proto,
  132. const TJson2ProtoConfig& config = TJson2ProtoConfig());
  133. /// @throw yexception
  134. inline void Json2Proto(const TString& json, google::protobuf::Message& proto,
  135. const TJson2ProtoConfig& config = TJson2ProtoConfig()) {
  136. Json2Proto(TStringBuf(json), proto, config);
  137. }
  138. /// @throw yexception
  139. inline void Json2Proto(IInputStream& in, google::protobuf::Message& proto,
  140. const TJson2ProtoConfig& config = TJson2ProtoConfig()) {
  141. Json2Proto(TStringBuf(in.ReadAll()), proto, config);
  142. }
  143. /// @throw yexception
  144. template <typename T>
  145. T Json2Proto(IInputStream& in, const NJson::TJsonReaderConfig& readerConfig,
  146. const TJson2ProtoConfig& config = TJson2ProtoConfig()) {
  147. NJson::TJsonValue jsonValue;
  148. NJson::ReadJsonTree(&in, &readerConfig, &jsonValue, true);
  149. T protoValue;
  150. Json2Proto(jsonValue, protoValue, config);
  151. return protoValue;
  152. }
  153. /// @throw yexception
  154. template <typename T>
  155. T Json2Proto(IInputStream& in, const TJson2ProtoConfig& config = TJson2ProtoConfig()) {
  156. NJson::TJsonReaderConfig readerConfig;
  157. readerConfig.DontValidateUtf8 = true;
  158. return Json2Proto<T>(in, readerConfig, config);
  159. }
  160. /// @throw yexception
  161. template <typename T>
  162. T Json2Proto(const TString& value, const TJson2ProtoConfig& config = TJson2ProtoConfig()) {
  163. TStringInput in(value);
  164. return Json2Proto<T>(in, config);
  165. }
  166. /// @throw yexception
  167. template <typename T>
  168. T Json2Proto(const TStringBuf& value, const TJson2ProtoConfig& config = TJson2ProtoConfig()) {
  169. TMemoryInput in(value);
  170. return Json2Proto<T>(in, config);
  171. }
  172. /// @throw yexception
  173. template <typename T>
  174. T Json2Proto(const char* ptr, const TJson2ProtoConfig& config = TJson2ProtoConfig()) {
  175. return Json2Proto<T>(TStringBuf(ptr), config);
  176. }
  177. }