1 // Copyright 2020 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #ifndef GRPC_SRC_CORE_LIB_JSON_JSON_OBJECT_LOADER_H
16 #define GRPC_SRC_CORE_LIB_JSON_JSON_OBJECT_LOADER_H
17
18 #include <grpc/support/port_platform.h>
19
20 #include <cstdint>
21 #include <cstring>
22 #include <map>
23 #include <memory>
24 #include <string>
25 #include <utility>
26 #include <vector>
27
28 #include "absl/meta/type_traits.h"
29 #include "absl/status/status.h"
30 #include "absl/status/statusor.h"
31 #include "absl/strings/numbers.h"
32 #include "absl/strings/str_cat.h"
33 #include "absl/strings/string_view.h"
34 #include "absl/types/optional.h"
35
36 #include "src/core/lib/gprpp/no_destruct.h"
37 #include "src/core/lib/gprpp/ref_counted_ptr.h"
38 #include "src/core/lib/gprpp/time.h"
39 #include "src/core/lib/gprpp/validation_errors.h"
40 #include "src/core/lib/json/json.h"
41 #include "src/core/lib/json/json_args.h"
42
43 // Provides a means to load JSON objects into C++ objects, with the aim of
44 // minimizing object code size.
45 //
46 // Usage:
47 // Given struct Foo:
48 // struct Foo {
49 // int a;
50 // int b;
51 // };
52 // We add a static JsonLoader() method to Foo to declare how to load the
53 // object from JSON, and an optional JsonPostLoad() method to do any
54 // necessary post-processing:
55 // struct Foo {
56 // int a;
57 // int b;
58 // static const JsonLoaderInterface* JsonLoader(const JsonArgs& args) {
59 // // Note: Field names must be string constants; they are not copied.
60 // static const auto* loader = JsonObjectLoader<Foo>()
61 // .Field("a", &Foo::a)
62 // .Field("b", &Foo::b)
63 // .Finish();
64 // return loader;
65 // }
66 // // Optional; omit if no post-processing needed.
67 // void JsonPostLoad(const Json& source, const JsonArgs& args,
68 // ValidationErrors* errors) {
69 // ++a;
70 // }
71 // };
72 // Now we can load Foo objects from JSON:
73 // absl::StatusOr<Foo> foo = LoadFromJson<Foo>(json);
74 namespace grpc_core {
75
76 namespace json_detail {
77
78 // An un-typed JSON loader.
79 class LoaderInterface {
80 public:
81 // Convert json value to whatever type we're loading at dst.
82 // If errors occur, add them to errors.
83 virtual void LoadInto(const Json& json, const JsonArgs& args, void* dst,
84 ValidationErrors* errors) const = 0;
85
86 protected:
87 ~LoaderInterface() = default;
88 };
89
90 // Loads a scalar (string or number).
91 class LoadScalar : public LoaderInterface {
92 public:
93 void LoadInto(const Json& json, const JsonArgs& args, void* dst,
94 ValidationErrors* errors) const override;
95
96 protected:
97 ~LoadScalar() = default;
98
99 private:
100 // true if we're loading a number, false if we're loading a string.
101 // We use a virtual function to store this decision in a vtable instead of
102 // needing an instance variable.
103 virtual bool IsNumber() const = 0;
104
105 virtual void LoadInto(const std::string& json, void* dst,
106 ValidationErrors* errors) const = 0;
107 };
108
109 // Load a string.
110 class LoadString : public LoadScalar {
111 protected:
112 ~LoadString() = default;
113
114 private:
115 bool IsNumber() const override;
116 void LoadInto(const std::string& value, void* dst,
117 ValidationErrors* errors) const override;
118 };
119
120 // Load a Duration.
121 class LoadDuration : public LoadScalar {
122 protected:
123 ~LoadDuration() = default;
124
125 private:
126 bool IsNumber() const override;
127 void LoadInto(const std::string& value, void* dst,
128 ValidationErrors* errors) const override;
129 };
130
131 // Load a number.
132 class LoadNumber : public LoadScalar {
133 protected:
134 ~LoadNumber() = default;
135
136 private:
137 bool IsNumber() const override;
138 };
139
140 // Load a signed number of type T.
141 template <typename T>
142 class TypedLoadSignedNumber : public LoadNumber {
143 protected:
144 ~TypedLoadSignedNumber() = default;
145
146 private:
LoadInto(const std::string & value,void * dst,ValidationErrors * errors)147 void LoadInto(const std::string& value, void* dst,
148 ValidationErrors* errors) const override {
149 if (!absl::SimpleAtoi(value, static_cast<T*>(dst))) {
150 errors->AddError("failed to parse number");
151 }
152 }
153 };
154
155 // Load an unsigned number of type T.
156 template <typename T>
157 class TypedLoadUnsignedNumber : public LoadNumber {
158 protected:
159 ~TypedLoadUnsignedNumber() = default;
160
161 private:
LoadInto(const std::string & value,void * dst,ValidationErrors * errors)162 void LoadInto(const std::string& value, void* dst,
163 ValidationErrors* errors) const override {
164 if (!absl::SimpleAtoi(value, static_cast<T*>(dst))) {
165 errors->AddError("failed to parse non-negative number");
166 }
167 }
168 };
169
170 // Load a float.
171 class LoadFloat : public LoadNumber {
172 protected:
173 ~LoadFloat() = default;
174
175 private:
LoadInto(const std::string & value,void * dst,ValidationErrors * errors)176 void LoadInto(const std::string& value, void* dst,
177 ValidationErrors* errors) const override {
178 if (!absl::SimpleAtof(value, static_cast<float*>(dst))) {
179 errors->AddError("failed to parse floating-point number");
180 }
181 }
182 };
183
184 // Load a double.
185 class LoadDouble : public LoadNumber {
186 protected:
187 ~LoadDouble() = default;
188
189 private:
LoadInto(const std::string & value,void * dst,ValidationErrors * errors)190 void LoadInto(const std::string& value, void* dst,
191 ValidationErrors* errors) const override {
192 if (!absl::SimpleAtod(value, static_cast<double*>(dst))) {
193 errors->AddError("failed to parse floating-point number");
194 }
195 }
196 };
197
198 // Load a bool.
199 class LoadBool : public LoaderInterface {
200 public:
201 void LoadInto(const Json& json, const JsonArgs& /*args*/, void* dst,
202 ValidationErrors* errors) const override;
203
204 protected:
205 ~LoadBool() = default;
206 };
207
208 // Loads an unprocessed JSON object value.
209 class LoadUnprocessedJsonObject : public LoaderInterface {
210 public:
211 void LoadInto(const Json& json, const JsonArgs& /*args*/, void* dst,
212 ValidationErrors* errors) const override;
213
214 protected:
215 ~LoadUnprocessedJsonObject() = default;
216 };
217
218 // Loads an unprocessed JSON array value.
219 class LoadUnprocessedJsonArray : public LoaderInterface {
220 public:
221 void LoadInto(const Json& json, const JsonArgs& /*args*/, void* dst,
222 ValidationErrors* errors) const override;
223
224 protected:
225 ~LoadUnprocessedJsonArray() = default;
226 };
227
228 // Load a vector of some type.
229 class LoadVector : public LoaderInterface {
230 public:
231 void LoadInto(const Json& json, const JsonArgs& args, void* dst,
232 ValidationErrors* errors) const override;
233
234 protected:
235 ~LoadVector() = default;
236
237 private:
238 virtual void* EmplaceBack(void* dst) const = 0;
239 virtual const LoaderInterface* ElementLoader() const = 0;
240 };
241
242 // Load a map of string->some type.
243 class LoadMap : public LoaderInterface {
244 public:
245 void LoadInto(const Json& json, const JsonArgs& args, void* dst,
246 ValidationErrors* errors) const override;
247
248 protected:
249 ~LoadMap() = default;
250
251 private:
252 virtual void* Insert(const std::string& name, void* dst) const = 0;
253 virtual const LoaderInterface* ElementLoader() const = 0;
254 };
255
256 // Load a wrapped value of some type.
257 class LoadWrapped : public LoaderInterface {
258 public:
259 void LoadInto(const Json& json, const JsonArgs& args, void* dst,
260 ValidationErrors* errors) const override;
261
262 protected:
263 ~LoadWrapped() = default;
264
265 private:
266 virtual void* Emplace(void* dst) const = 0;
267 virtual void Reset(void* dst) const = 0;
268 virtual const LoaderInterface* ElementLoader() const = 0;
269 };
270
271 // Fetch a LoaderInterface for some type.
272 template <typename T>
273 const LoaderInterface* LoaderForType();
274
275 // AutoLoader implements LoaderInterface for a type.
276 // The default asks the type for its LoaderInterface and then uses that.
277 // Classes that load from objects should provide a:
278 // static const JsonLoaderInterface* JsonLoader();
279 template <typename T>
280 class AutoLoader final : public LoaderInterface {
281 public:
LoadInto(const Json & json,const JsonArgs & args,void * dst,ValidationErrors * errors)282 void LoadInto(const Json& json, const JsonArgs& args, void* dst,
283 ValidationErrors* errors) const override {
284 T::JsonLoader(args)->LoadInto(json, args, dst, errors);
285 }
286
287 private:
288 ~AutoLoader() = default;
289 };
290
291 // Specializations of AutoLoader for basic types.
292 template <>
293 class AutoLoader<std::string> final : public LoadString {
294 private:
295 ~AutoLoader() = default;
296 };
297 template <>
298 class AutoLoader<Duration> final : public LoadDuration {
299 private:
300 ~AutoLoader() = default;
301 };
302 template <>
303 class AutoLoader<int32_t> final : public TypedLoadSignedNumber<int32_t> {
304 private:
305 ~AutoLoader() = default;
306 };
307 template <>
308 class AutoLoader<int64_t> final : public TypedLoadSignedNumber<int64_t> {
309 private:
310 ~AutoLoader() = default;
311 };
312 template <>
313 class AutoLoader<uint32_t> final : public TypedLoadUnsignedNumber<uint32_t> {
314 private:
315 ~AutoLoader() = default;
316 };
317 template <>
318 class AutoLoader<uint64_t> final : public TypedLoadUnsignedNumber<uint64_t> {
319 private:
320 ~AutoLoader() = default;
321 };
322 template <>
323 class AutoLoader<float> final : public LoadFloat {
324 private:
325 ~AutoLoader() = default;
326 };
327 template <>
328 class AutoLoader<double> final : public LoadDouble {
329 private:
330 ~AutoLoader() = default;
331 };
332 template <>
333 class AutoLoader<bool> final : public LoadBool {
334 private:
335 ~AutoLoader() = default;
336 };
337 template <>
338 class AutoLoader<Json::Object> final : public LoadUnprocessedJsonObject {
339 private:
340 ~AutoLoader() = default;
341 };
342 template <>
343 class AutoLoader<Json::Array> final : public LoadUnprocessedJsonArray {
344 private:
345 ~AutoLoader() = default;
346 };
347
348 // Specializations of AutoLoader for vectors.
349 template <typename T>
350 class AutoLoader<std::vector<T>> final : public LoadVector {
351 private:
352 ~AutoLoader() = default;
EmplaceBack(void * dst)353 void* EmplaceBack(void* dst) const final {
354 auto* vec = static_cast<std::vector<T>*>(dst);
355 vec->emplace_back();
356 return &vec->back();
357 }
ElementLoader()358 const LoaderInterface* ElementLoader() const final {
359 return LoaderForType<T>();
360 }
361 };
362
363 // Specialization of AutoLoader for vector<bool> - we need a different
364 // implementation because, as vector<bool> packs bits in its implementation, the
365 // technique of returning a void* from Emplace() for the generic vector loader
366 // doesn't work.
367 template <>
368 class AutoLoader<std::vector<bool>> final : public LoaderInterface {
369 public:
370 void LoadInto(const Json& json, const JsonArgs& args, void* dst,
371 ValidationErrors* errors) const override;
372
373 private:
374 ~AutoLoader() = default;
375 };
376
377 // Specializations of AutoLoader for maps.
378 template <typename T>
379 class AutoLoader<std::map<std::string, T>> final : public LoadMap {
380 private:
Insert(const std::string & name,void * dst)381 void* Insert(const std::string& name, void* dst) const final {
382 return &static_cast<std::map<std::string, T>*>(dst)
383 ->emplace(name, T())
384 .first->second;
385 };
ElementLoader()386 const LoaderInterface* ElementLoader() const final {
387 return LoaderForType<T>();
388 }
389
390 ~AutoLoader() = default;
391 };
392
393 // Specializations of AutoLoader for absl::optional<>.
394 template <typename T>
395 class AutoLoader<absl::optional<T>> final : public LoadWrapped {
396 public:
Emplace(void * dst)397 void* Emplace(void* dst) const final {
398 return &static_cast<absl::optional<T>*>(dst)->emplace();
399 }
Reset(void * dst)400 void Reset(void* dst) const final {
401 static_cast<absl::optional<T>*>(dst)->reset();
402 }
ElementLoader()403 const LoaderInterface* ElementLoader() const final {
404 return LoaderForType<T>();
405 }
406
407 private:
408 ~AutoLoader() = default;
409 };
410
411 // Specializations of AutoLoader for std::unique_ptr<>.
412 template <typename T>
413 class AutoLoader<std::unique_ptr<T>> final : public LoadWrapped {
414 public:
Emplace(void * dst)415 void* Emplace(void* dst) const final {
416 auto& p = *static_cast<std::unique_ptr<T>*>(dst);
417 p = std::make_unique<T>();
418 return p.get();
419 }
Reset(void * dst)420 void Reset(void* dst) const final {
421 static_cast<std::unique_ptr<T>*>(dst)->reset();
422 }
ElementLoader()423 const LoaderInterface* ElementLoader() const final {
424 return LoaderForType<T>();
425 }
426
427 private:
428 ~AutoLoader() = default;
429 };
430
431 // Specializations of AutoLoader for RefCountedPtr<>.
432 template <typename T>
433 class AutoLoader<RefCountedPtr<T>> final : public LoadWrapped {
434 public:
Emplace(void * dst)435 void* Emplace(void* dst) const final {
436 auto& p = *static_cast<RefCountedPtr<T>*>(dst);
437 p = MakeRefCounted<T>();
438 return p.get();
439 }
Reset(void * dst)440 void Reset(void* dst) const final {
441 static_cast<RefCountedPtr<T>*>(dst)->reset();
442 }
ElementLoader()443 const LoaderInterface* ElementLoader() const final {
444 return LoaderForType<T>();
445 }
446
447 private:
448 ~AutoLoader() = default;
449 };
450
451 // Implementation of aforementioned LoaderForType.
452 // Simply keeps a static AutoLoader<T> and returns a pointer to that.
453 template <typename T>
LoaderForType()454 const LoaderInterface* LoaderForType() {
455 return NoDestructSingleton<AutoLoader<T>>::Get();
456 }
457
458 // Element describes one typed field to be loaded from a JSON object.
459 struct Element {
460 Element() = default;
461 template <typename A, typename B>
ElementElement462 Element(const char* name, bool optional, B A::*p,
463 const LoaderInterface* loader, const char* enable_key)
464 : loader(loader),
465 member_offset(static_cast<uint16_t>(
466 reinterpret_cast<uintptr_t>(&(static_cast<A*>(nullptr)->*p)))),
467 optional(optional),
468 name(name),
469 enable_key(enable_key) {}
470 // The loader for this field.
471 const LoaderInterface* loader;
472 // Offset into the destination object to store the field.
473 uint16_t member_offset;
474 // Is this field optional?
475 bool optional;
476 // The name of the field.
477 const char* name;
478 // The key to use with JsonArgs to see if this field is enabled.
479 const char* enable_key;
480 };
481
482 // Vec<T, kSize> provides a constant array type that can be appended to by
483 // copying. It's setup so that most compilers can optimize away all of its
484 // operations.
485 template <typename T, size_t kSize>
486 class Vec {
487 public:
Vec(const Vec<T,kSize-1> & other,const T & new_value)488 Vec(const Vec<T, kSize - 1>& other, const T& new_value) {
489 for (size_t i = 0; i < other.size(); i++) values_[i] = other.data()[i];
490 values_[kSize - 1] = new_value;
491 }
492
data()493 const T* data() const { return values_; }
size()494 size_t size() const { return kSize; }
495
496 private:
497 T values_[kSize];
498 };
499
500 template <typename T>
501 class Vec<T, 0> {
502 public:
data()503 const T* data() const { return nullptr; }
size()504 size_t size() const { return 0; }
505 };
506
507 // Given a list of elements, and a destination object, load the elements into
508 // the object from some parsed JSON.
509 // Returns false if the JSON object was not of type Json::Type::kObject.
510 bool LoadObject(const Json& json, const JsonArgs& args, const Element* elements,
511 size_t num_elements, void* dst, ValidationErrors* errors);
512
513 // Adaptor type - takes a compile time computed list of elements and
514 // implements LoaderInterface by calling LoadObject.
515 template <typename T, size_t kElemCount, typename Hidden = void>
516 class FinishedJsonObjectLoader final : public LoaderInterface {
517 public:
FinishedJsonObjectLoader(const Vec<Element,kElemCount> & elements)518 explicit FinishedJsonObjectLoader(const Vec<Element, kElemCount>& elements)
519 : elements_(elements) {}
520
LoadInto(const Json & json,const JsonArgs & args,void * dst,ValidationErrors * errors)521 void LoadInto(const Json& json, const JsonArgs& args, void* dst,
522 ValidationErrors* errors) const override {
523 LoadObject(json, args, elements_.data(), elements_.size(), dst, errors);
524 }
525
526 private:
527 GPR_NO_UNIQUE_ADDRESS Vec<Element, kElemCount> elements_;
528 };
529
530 // Specialization for when the object has a JsonPostLoad function exposed.
531 template <typename T, size_t kElemCount>
532 class FinishedJsonObjectLoader<T, kElemCount,
533 absl::void_t<decltype(&T::JsonPostLoad)>>
534 final : public LoaderInterface {
535 public:
FinishedJsonObjectLoader(const Vec<Element,kElemCount> & elements)536 explicit FinishedJsonObjectLoader(const Vec<Element, kElemCount>& elements)
537 : elements_(elements) {}
538
LoadInto(const Json & json,const JsonArgs & args,void * dst,ValidationErrors * errors)539 void LoadInto(const Json& json, const JsonArgs& args, void* dst,
540 ValidationErrors* errors) const override {
541 // Call JsonPostLoad() only if json is a JSON object.
542 if (LoadObject(json, args, elements_.data(), elements_.size(), dst,
543 errors)) {
544 static_cast<T*>(dst)->JsonPostLoad(json, args, errors);
545 }
546 }
547
548 private:
549 GPR_NO_UNIQUE_ADDRESS Vec<Element, kElemCount> elements_;
550 };
551
552 // Builder type for JSON object loaders.
553 // Concatenate fields with Field, OptionalField, and then call Finish to
554 // obtain an object that implements LoaderInterface.
555 template <typename T, size_t kElemCount = 0>
556 class JsonObjectLoader final {
557 public:
JsonObjectLoader()558 JsonObjectLoader() {
559 static_assert(kElemCount == 0,
560 "Only initial loader step can have kElemCount==0.");
561 }
562
Finish()563 FinishedJsonObjectLoader<T, kElemCount>* Finish() const {
564 return new FinishedJsonObjectLoader<T, kElemCount>(elements_);
565 }
566
567 template <typename U>
568 JsonObjectLoader<T, kElemCount + 1> Field(
569 const char* name, U T::*p, const char* enable_key = nullptr) const {
570 return Field(name, false, p, enable_key);
571 }
572
573 template <typename U>
574 JsonObjectLoader<T, kElemCount + 1> OptionalField(
575 const char* name, U T::*p, const char* enable_key = nullptr) const {
576 return Field(name, true, p, enable_key);
577 }
578
JsonObjectLoader(const Vec<Element,kElemCount-1> & elements,Element new_element)579 JsonObjectLoader(const Vec<Element, kElemCount - 1>& elements,
580 Element new_element)
581 : elements_(elements, new_element) {}
582
583 private:
584 template <typename U>
Field(const char * name,bool optional,U T::* p,const char * enable_key)585 JsonObjectLoader<T, kElemCount + 1> Field(const char* name, bool optional,
586 U T::*p,
587 const char* enable_key) const {
588 return JsonObjectLoader<T, kElemCount + 1>(
589 elements_, Element(name, optional, p, LoaderForType<U>(), enable_key));
590 }
591
592 GPR_NO_UNIQUE_ADDRESS Vec<Element, kElemCount> elements_;
593 };
594
595 const Json* GetJsonObjectField(const Json::Object& json,
596 absl::string_view field,
597 ValidationErrors* errors, bool required);
598
599 } // namespace json_detail
600
601 template <typename T>
602 using JsonObjectLoader = json_detail::JsonObjectLoader<T>;
603
604 using JsonLoaderInterface = json_detail::LoaderInterface;
605
606 template <typename T>
607 absl::StatusOr<T> LoadFromJson(
608 const Json& json, const JsonArgs& args = JsonArgs(),
609 absl::string_view error_prefix = "errors validating JSON") {
610 ValidationErrors errors;
611 T result{};
612 json_detail::LoaderForType<T>()->LoadInto(json, args, &result, &errors);
613 if (!errors.ok()) {
614 return errors.status(absl::StatusCode::kInvalidArgument, error_prefix);
615 }
616 return std::move(result);
617 }
618
619 template <typename T>
LoadFromJson(const Json & json,const JsonArgs & args,ValidationErrors * errors)620 T LoadFromJson(const Json& json, const JsonArgs& args,
621 ValidationErrors* errors) {
622 T result{};
623 json_detail::LoaderForType<T>()->LoadInto(json, args, &result, errors);
624 return result;
625 }
626
627 template <typename T>
628 absl::optional<T> LoadJsonObjectField(const Json::Object& json,
629 const JsonArgs& args,
630 absl::string_view field,
631 ValidationErrors* errors,
632 bool required = true) {
633 ValidationErrors::ScopedField error_field(errors, absl::StrCat(".", field));
634 const Json* field_json =
635 json_detail::GetJsonObjectField(json, field, errors, required);
636 if (field_json == nullptr) return absl::nullopt;
637 T result{};
638 size_t starting_error_size = errors->size();
639 json_detail::LoaderForType<T>()->LoadInto(*field_json, args, &result, errors);
640 if (errors->size() > starting_error_size) return absl::nullopt;
641 return std::move(result);
642 }
643
644 } // namespace grpc_core
645
646 #endif // GRPC_SRC_CORE_LIB_JSON_JSON_OBJECT_LOADER_H
647