json2proto.h 8.7 KB

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