proxygen
folly::DynamicParser Class Reference

#include <DynamicParser.h>

Classes

struct  ParserStack
 

Public Types

enum  OnError { OnError::RECORD, OnError::THROW }
 

Public Member Functions

 DynamicParser (OnError on_error, const folly::dynamic *d)
 
folly::dynamic releaseErrors ()
 
template<typename Fn >
void optional (const folly::dynamic &key, Fn)
 
template<typename Fn >
void required (const folly::dynamic &key, Fn)
 
template<typename Fn >
void objectItems (Fn)
 
template<typename Fn >
void arrayItems (Fn)
 
const folly::dynamickey () const
 
const folly::dynamicvalue () const
 
DynamicParsersetAllowNonStringKeyErrors (bool b)
 

Private Member Functions

template<typename Fn >
void wrapError (const folly::dynamic *lookup_key, Fn)
 
void reportError (const folly::dynamic *lookup_k, const std::exception &ex)
 
template<typename Fn >
void parse (const folly::dynamic &key, const folly::dynamic &value, Fn fn)
 

Private Attributes

OnError onError_
 
ParserStack stack_
 
bool allowNonStringKeyErrors_ {false}
 

Detailed Description

Definition at line 229 of file DynamicParser.h.

Member Enumeration Documentation

Enumerator
RECORD 
THROW 

Definition at line 231 of file DynamicParser.h.

231  {
232  // After parsing, releaseErrors() reports all parse errors.
233  // Throws DynamicParserLogicError on programmer errors.
234  RECORD,
235  // Throws DynamicParserParseError on the first parse error, or
236  // DynamicParserLogicError on programmer errors.
237  THROW,
238  };

Constructor & Destructor Documentation

folly::DynamicParser::DynamicParser ( OnError  on_error,
const folly::dynamic d 
)
inline

Definition at line 241 of file DynamicParser.h.

242  : onError_(on_error), stack_(d) {} // Always access input through stack_
auto on_error(Fns...fns) -> on_error_fn< Fns... >
Definition: boosters.h:273

Member Function Documentation

template<typename Fn >
void folly::DynamicParser::arrayItems ( Fn  fn)

Like objectItems() – arrays are treated identically to objects with integer keys from 0 to size() - 1.

Definition at line 280 of file DynamicParser-inl.h.

References i, parse(), and folly::value().

Referenced by TEST().

280  {
281  wrapError(nullptr, [&]() {
282  size_t i = 0;
283  for (const auto& v : value()) { // Iteration can throw
284  parse(i, v, fn); // i => dynamic cannot throw
285  ++i;
286  }
287  });
288 }
void wrapError(const folly::dynamic *lookup_key, Fn)
const folly::dynamic & value() const
void parse(const folly::dynamic &key, const folly::dynamic &value, Fn fn)
const folly::dynamic& folly::DynamicParser::key ( ) const
inline

The key currently being parsed (integer if inside an array). Throws if called outside of a parser callback.

Definition at line 283 of file DynamicParser.h.

References stack_.

Referenced by TEST().

283  {
284  return stack_.key();
285  }
const folly::dynamic & key() const
template<typename Fn >
void folly::DynamicParser::objectItems ( Fn  fn)

Iterate over the current object's keys and values. Report each item's errors under its own key in a matching sub-object of "errors".

Definition at line 271 of file DynamicParser-inl.h.

References parse(), and folly::value().

Referenced by TEST().

271  {
272  wrapError(nullptr, [&]() {
273  for (const auto& kv : value().items()) { // .items() can throw
274  parse(kv.first, kv.second, fn);
275  }
276  });
277 }
void wrapError(const folly::dynamic *lookup_key, Fn)
const folly::dynamic & value() const
void parse(const folly::dynamic &key, const folly::dynamic &value, Fn fn)
template<typename Fn >
void folly::DynamicParser::optional ( const folly::dynamic key,
Fn  fn 
)

Error-wraps fn(auto-converted key & value) if d[key] is set. The top-of-file docblock explains the auto-conversion.

Definition at line 244 of file DynamicParser-inl.h.

References folly::get_ptr(), parse(), and folly::value().

Referenced by TEST().

244  {
245  wrapError(&key, [&]() {
246  if (auto vp = value().get_ptr(key)) {
247  parse(key, *vp, fn);
248  }
249  });
250 }
const Map::mapped_type * get_ptr(const Map &map, const Key &key)
Definition: MapUtil.h:169
void wrapError(const folly::dynamic *lookup_key, Fn)
const folly::dynamic & value() const
void parse(const folly::dynamic &key, const folly::dynamic &value, Fn fn)
template<typename Fn >
void folly::DynamicParser::parse ( const folly::dynamic key,
const folly::dynamic value,
Fn  fn 
)
private

Definition at line 307 of file DynamicParser-inl.h.

References folly::gen::guard(), folly::detail::invokeForKeyValue(), and stack_.

310  {
311  auto guard = stack_.push(k, v); // User code can nest parser calls.
312  wrapError(nullptr, [&]() { detail::invokeForKeyValue(fn, k, v); });
313 }
EnableForArgTypes< Fn > invokeForKeyValue(Fn f, const folly::dynamic &, const folly::dynamic &)
void wrapError(const folly::dynamic *lookup_key, Fn)
GuardImpl guard(ErrorHandler &&handler)
Definition: Base.h:840
PopGuard push(const folly::dynamic &k, const folly::dynamic &v) noexcept
KeyT k
folly::dynamic folly::DynamicParser::releaseErrors ( )
inline

Once you finished the entire parse, returns a structured description of all parse errors (see top-of-file docblock). May ONLY be called once. May NOT be called if the parse threw any kind of exception. Returns an empty object for successful OnError::THROW parsers.

Definition at line 250 of file DynamicParser.h.

References stack_.

Referenced by checkItemParseError(), checkMaybeCoercedKeys(), checkXYKeyErrorsAndParseError(), and TEST().

250  {
251  return stack_.releaseErrors();
252  }
void folly::DynamicParser::reportError ( const folly::dynamic lookup_k,
const std::exception &  ex 
)
private

Definition at line 53 of file DynamicParser.cpp.

References allowNonStringKeyErrors_, folly::DynamicParser::ParserStack::errors(), folly::FATAL, folly::dynamic::object(), onError_, RECORD, stack_, THROW, folly::DynamicParser::ParserStack::throwErrors(), folly::detail::toPseudoJson(), and value().

55  {
56  // If descendants of this item, or other keys on it, already reported an
57  // error, the error object would already exist.
59 
60  // Save the original, unparseable value of the item causing the error.
61  //
62  // value() can throw here, but if it does, it is due to programmer error,
63  // so we don't want to report it as a parse error anyway.
64  if (auto* e_val_ptr = e.get_ptr("value")) {
65  // Failing to access distinct keys on the same value can generate
66  // multiple errors, but the value should remain the same.
67  if (*e_val_ptr != value()) {
68  throw DynamicParserLogicError(
69  "Overwriting value: ",
70  detail::toPseudoJson(*e_val_ptr),
71  " with ",
73  " for error ",
74  ex.what());
75  }
76  } else {
77  // The e["value"].isNull() trick cannot be used because value().type()
78  // *can* be folly::dynamic::Type::NULLT, so we must hash again.
79  e["value"] = value();
80  }
81 
82  // Differentiate between "parsing value" and "looking up key" errors.
83  auto& e_msg = [&]() -> folly::dynamic& {
84  if (lookup_k == nullptr) { // {object,array}Items, or post-key-lookup
85  return e["error"];
86  }
87  // Multiple key lookups can report errors on the same collection.
88  auto& key_errors = e["key_errors"];
89  if (key_errors.isNull()) {
90  // Treat arrays as integer-keyed objects.
91  key_errors = folly::dynamic::object();
92  }
93  return insertAtKey(&key_errors, allowNonStringKeyErrors_, *lookup_k);
94  }();
95  if (!e_msg.isNull()) {
96  throw DynamicParserLogicError(
97  "Overwriting error: ",
98  detail::toPseudoJson(e_msg),
99  " with: ",
100  ex.what());
101  }
102  e_msg = ex.what();
103 
104  switch (onError_) {
105  case OnError::RECORD:
106  break; // Continue parsing
107  case OnError::THROW:
108  stack_.throwErrors(); // Package releaseErrors() into an exception.
109  default:
110  LOG(FATAL) << "Bad onError_: " << static_cast<int>(onError_);
111  }
112 }
static ObjectMaker object()
Definition: dynamic-inl.h:240
const folly::dynamic & value() const
std::string toPseudoJson(const folly::dynamic &d)
folly::dynamic & errors(bool allow_non_string_keys) noexcept
template<typename Fn >
void folly::DynamicParser::required ( const folly::dynamic key,
Fn  fn 
)

Definition at line 257 of file DynamicParser-inl.h.

References parse(), folly::detail::toPseudoJson(), and folly::value().

Referenced by checkMaybeCoercedKeys(), and TEST().

257  {
258  wrapError(&key, [&]() {
259  auto vp = value().get_ptr(key);
260  if (!vp) {
261  throw std::runtime_error(folly::to<std::string>(
262  "Couldn't find key ",
264  " in dynamic object"));
265  }
266  parse(key, *vp, fn);
267  });
268 }
void wrapError(const folly::dynamic *lookup_key, Fn)
const folly::dynamic & value() const
std::string toPseudoJson(const folly::dynamic &d)
void parse(const folly::dynamic &key, const folly::dynamic &value, Fn fn)
const dynamic * get_ptr(json_pointer const &) const &
Definition: dynamic.cpp:371
DynamicParser& folly::DynamicParser::setAllowNonStringKeyErrors ( bool  b)
inline

By default, DynamicParser's "nested" object coerces all keys to strings, whether from arrayItems() or from p.optional(some_int, ...), to allow errors be serialized to JSON. If you are parsing non-JSON dynamic objects with non-string keys, this is problematic. When set to true, "nested" objects will report integer keys for errors coming from inside arrays, or the original key type from inside values of objects.

Definition at line 302 of file DynamicParser.h.

References b, parse(), and folly::value().

Referenced by checkMaybeCoercedKeys().

302  {
304  return *this;
305  }
char b
const folly::dynamic& folly::DynamicParser::value ( ) const
inline

The value currently being parsed (initially, the input dynamic). Throws if parsing nullptr, or parsing after releaseErrors().

Definition at line 290 of file DynamicParser.h.

References stack_.

Referenced by reportError(), and TEST().

290  {
291  return stack_.value();
292  }
const folly::dynamic & value() const
template<typename Fn >
void folly::DynamicParser::wrapError ( const folly::dynamic lookup_key,
Fn  fn 
)
private

If fn throws an exception, wrapError() catches it and inserts an enriched description into stack_.errors_. If lookup_key is non-null, reports a key lookup error in "key_errors", otherwise reportse a value error in "error".

Not public because that would encourage users to report multiple errors per input part, which is currently unsupported. It does not currently seem like normal user code should need this.

Definition at line 291 of file DynamicParser-inl.h.

291  {
292  try {
293  fn();
294  } catch (DynamicParserLogicError&) {
295  // When the parser is misused, we throw all the way up to the user,
296  // instead of reporting it as if the input is invalid.
297  throw;
298  } catch (DynamicParserParseError&) {
299  // We are just bubbling up a parse error for OnError::THROW.
300  throw;
301  } catch (const std::exception& ex) {
302  reportError(lookup_k, ex);
303  }
304 }
void reportError(const folly::dynamic *lookup_k, const std::exception &ex)

Member Data Documentation

bool folly::DynamicParser::allowNonStringKeyErrors_ {false}
private

Definition at line 408 of file DynamicParser.h.

Referenced by reportError().

OnError folly::DynamicParser::onError_
private

Definition at line 406 of file DynamicParser.h.

Referenced by reportError().

ParserStack folly::DynamicParser::stack_
private

Definition at line 407 of file DynamicParser.h.

Referenced by reportError().


The documentation for this class was generated from the following files: