/* This file is part of MAUS: http://micewww.pp.rl.ac.uk:8080/projects/maus * * MAUS is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * MAUS is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with MAUS. If not, see . * */ /** @class JsonWrapper * \brief Wrap the Json function calls with additional error handling * * Convenience wrapper for Json functionality. Use of Json is somewhat verbose * and requires lots of error checking etc. I wrap the Json function calls here * in order to reduce verbosity. * * Nb jargon: * * Json "object" is like a map. * * Json "array" is a dynamic length array */ #ifndef _SRC_CPP_CORE_UTILS_JSONWRAPPER_HH #define _SRC_CPP_CORE_UTILS_JSONWRAPPER_HH #include #include #include "json/json.h" #include "CLHEP/Vector/ThreeVector.h" #include "src/legacy/Interface/STLUtils.hh" #include "Utils/Exception.hh" namespace JsonWrapper { /** @brief List of data types allowed by json * * List of data types allowed by json, with additional type "anyValue" for * when we don't care. * * Note Json always assumes integers are signed */ enum JsonType { nullValue, // 'null' value uintValue, // unsigned integer value intValue, // signed integer value realValue, // double value stringValue, // UTF-8 string value booleanValue, // bool value arrayValue, // array value (ordered list) objectValue, // object value (collection of name/value pairs) anyValue // object value (collection of name/value pairs) }; /** @brief Convert a string to a Json::Value tree * * @param json_in raw string holding the configuration information * * Read in a string and return as a Json value. Throw a Exception if the reader * fails to parse the string. The configuration is a dict of Json::Value, * which is in itself a Json::Value. */ Json::Value StringToJson(const std::string& json_in) throw(MAUS::Exceptions::Exception); /** @brief Convert a Json::Value tree to a std::string * * @param json_in Json::Value to convert to a string */ std::string JsonToString(const Json::Value& val); /** @brief Get an item from a Json array (variable length array) * * @param array array of values from which we want to get a value * @param value_index index of the value in the array * @param value_type type of the value we want to get * * Returns the Json::Value on success. Throws an exception of type Exception on * failure */ Json::Value GetItem(const Json::Value& array, const size_t value_index, const JsonType value_type) throw(MAUS::Exceptions::Exception); /** @brief Get a property from a Json object (hash) * * @param object the Json data tree * @param value_name name of the branch we want to get * @param value_type type of the value we want to get * * Attempt to access a branch from Json. If the branch is not found, throw a * Exception. */ Json::Value GetProperty(const Json::Value& object, const std::string& value_name, const JsonType value_type) throw(MAUS::Exceptions::Exception); /** @brief Convert from a json three vector to a CLHEP three vector * * @param json_vec objectValue with realValue children "x", "y", "z". Throws * an exception if the conversion fails. */ CLHEP::Hep3Vector JsonToThreeVector(const Json::Value& json_vec) throw(MAUS::Exceptions::Exception); /** @brief Convert from Json::ValueType to JsonType */ JsonType ValueTypeToJsonType(const Json::ValueType tp); /** @brief Convert from Json::Value type to string */ std::string ValueTypeToString(const Json::ValueType tp); /** @brief Convert from JsonType to Json::ValueType */ Json::ValueType JsonTypeToValueType(const JsonType tp) throw(MAUS::Exceptions::Exception); /** @brief Return true if cast_target can be cast to cast_type in a safe way * * Return true if the target can be cast to cast_type without loss of data, * i.e. int, uint can be cast to float; uint can be cast to int; anything can * be cast to anyValue and we allow anyValue to be cast back to anything. */ bool SimilarType(const JsonType cast_target, const JsonType cast_type); /** @brief Return true if types are numeric (integer or float) */ bool IsNumeric(const JsonType jt); /** @brief Print the Json value to an ostream * * Prints in json format to ostream out; so if passed to a stringstream, then * StringToJson should read back in with no change */ void Print(std::ostream& out, const Json::Value& val); /** @brief Check for equality between json values * * Check that value_1 == value_2; when comparing reals, we allow a float * tolerance given by tolerance. Recursively search through arrays and * objects. * * @param tolerance float tolerance - requirement is that * fabs(float_1-float_2) < tolerance * @param int_permissive return true even if a is an int and b is a * uint (recursively) */ bool AlmostEqual(const Json::Value& value_1, const Json::Value& value_2, const double tolerance, bool int_permissive = false); /** @brief Check for equality between json arrays * * Check that value_1 == value_2, within float tolerance. Note that there is * no type checking done here. * * @param tolerance float tolerance - requirement is that * fabs(float_1-float_2) < tolerance * @param int_permissive return true even if a is an int and b is a * uint (recursively) */ bool ArrayEqual(const Json::Value& value_1, const Json::Value& value_2, const double tolerance, bool int_permissive = false); /** @brief Check for equality between json objects * * Check that value_1 == value_2, within float tolerance. Note that there is * no type checking done here. * * @param tolerance float tolerance - requirement is that * fabs(float_1-float_2) < tolerance * @param int_permissive return true even if a is an int and b is a * uint (recursively) */ bool ObjectEqual(const Json::Value& value_1, const Json::Value& value_2, const double tolerance, bool int_permissive = false); /** @brief Merge two json objects * * Merge two json objects. For each property in the object; if the property * exists in object_1 or object_2 and is an array, append items from object_2 * array onto the back of the object_1 array; if the property exists in one * object but not the other put it in the merged object; if the property * exists in both objects but is not an array, throw an exception. */ Json::Value ObjectMerge(const Json::Value& object_1, const Json::Value& object_2); /** @brief Merge two json arrays * * Put items from array_2 onto the back of array_1 */ Json::Value ArrayMerge(const Json::Value& array_1, const Json::Value& array_2); namespace Path { // Nb: Path could be a class? But then we lose "using" functionality; OTOH we // can make things properly private... /** @brief Get the path from a json value * * Path is stored in the comment field */ std::string GetPath(const Json::Value& json); /** @brief Set the path to a json value * * Path is stored in the comment field */ void SetPath(Json::Value& json, const std::string& path); /** @brief Append the path to a json value * * Path is stored in the comment field * \param json Json::Value to which the path should be appended * \param branch_name name of a branch in a Json object */ void AppendPath(Json::Value& json, const std::string& branch_name); /** @brief Append the path to a json value * * Path is stored in the comment field * \param json Json::Value to which the path should be appended * \param array_index index of a branch in a Json array */ void AppendPath(Json::Value& json, const size_t array_index); /** @brief Return the json value corresponding to a given path * * Return the json value located at a given path. If the path cannot be * accessed, throw a Exception. */ Json::Value& DereferencePath(Json::Value& json, const std::string& path); /** @brief walk the Json structure setting path on all data * * @param value json tree that will have path set * @param root_path path from root; all subsequent paths will be appended to * this one (set to "" to start from root) */ void SetPathRecursive(Json::Value& json, const std::string& root_path); /** @brief walk the Json structure stripping comments from all data * * Metadata on json objects is stored in path information. This function * walks the data structure and strips out those comments. */ void StripPathRecursive(Json::Value& json); /** Private - do not call */ void _SetPathRecursive(Json::Value& json); } // namespace Path } // namespace JsonWrapper #endif