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