open-source-parsers / open-source-parsers/jsoncpp

Serialization

Open
#1,492 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C++
Stars
8.9k
Forks
2.7k
Avg merge
31m
Merged PRs (30d)
1

Description

Hello, it's the first time I create an issue under an opensource.
We use jsoncpp 0.5.0 version as a third lib. Recently I realize json to struct function base on jsoncpp's Json::Value.
Here is my serializer.h.

namespace Json {

template <typename T, T... S, typename F>
constexpr void for_sequence(std::integer_sequence<T, S...>, F&& f) {
	using unpack_t = int[];
	(void)unpack_t{(static_cast<void>(f(std::integral_constant<T, S>{})), 0)..., 0};
}

template<typename Class, typename T>
struct PropertyImpl {
  constexpr PropertyImpl(T Class::*aMember, const char* aName) : member{aMember}, name{aName} {}

  using Type = T;

  T Class::*member;
  const char* name;
};

template<typename Class, typename T>
constexpr auto property(T Class::*member, const char* name) {
  return PropertyImpl<Class, T>{member, name};
}

template<typename T>
struct PropertyTag {
  typedef char yes;
  typedef long no;
  template <typename TT>
  static auto CheckTag(int) -> decltype(std::declval<TT>().properties, yes());

  template <typename TT>
  static std::false_type CheckTag(...);
  static constexpr bool hasProperty = std::is_same<decltype(CheckTag<T>(0)), yes>::value;
};

template<typename T, typename std::enable_if<PropertyTag<T>::hasProperty, int>::type = 0>
T FromJson(const Json::Value& value);

template<typename T, typename std::enable_if<!PropertyTag<T>::hasProperty, int>::type = 0>
T FromJson(const Json::Value& value) {
    return T();
}

template<typename T, typename std::enable_if<PropertyTag<T>::hasProperty, int>::type = 0>
Json::Value ToJson(const T &object);

template<typename T, typename std::enable_if<!PropertyTag<T>::hasProperty, int>::type = 0>
Json::Value ToJson(const T &object) {
    return Json::Value();
}

template<typename T, typename std::enable_if<PropertyTag<T>::hasProperty, int>::type = 0> 
inline T asAny(const Json::Value& value) {
  return FromJson<T>(value);
}

template <typename T, typename std::enable_if<!PropertyTag<T>::hasProperty, int>::type = 0>
inline T asAny(const Json::Value& value) {
  return T{};
}

template<>
inline int asAny<int>(const Json::Value& value) {
  return value.asInt();
}

template<>
inline std::string asAny<std::string>(const Json::Value& value) {
  return value.asString();
}

template<>
inline char* asAny<char*>(const Json::Value& value) {
    if (value.type() != Json::stringValue) {
        return "";
    }
    return const_cast<char*>(value.asCString());
}

template<>
inline bool asAny<bool>(const Json::Value& value) {
  return value.asBool();
}

template<>
inline double asAny<double>(const Json::Value& value) {
  return value.asDouble();
}

template<>
inline float asAny<float>(const Json::Value& value) {
  return value.asDouble();
}

template<>
inline uint asAny<uint>(const Json::Value& value) {
  return value.asUInt();
}

template<>
inline std::vector<std::string> asAny<std::vector<std::string>>(const Json::Value& value) {
  std::vector<std::string> vec;
  if (value.isArray() && value.size() != 0) {
    for (uint i = 0; i < value.size(); ++i) {
      vec.push_back(value[i].asString());
    }
  }
  return vec;
}

template<>
inline std::vector<int> asAny<std::vector<int>>(const Json::Value& value) {
  std::vector<int> vec;
  if (value.isArray() && value.size() != 0) {
    for (uint i = 0; i < value.size(); ++i) {
      vec.push_back(value[i].asInt());
    }
  }
  return vec;
}

template <typename T, typename std::enable_if<PropertyTag<T>::hasProperty, int>::type = 0>
Json::Value convertJson(const T& object) {
  return ToJson(object);
}

template <typename T, typename std::enable_if<!PropertyTag<T>::hasProperty, int>::type = 0>
Json::Value convertJson(const T &object) {
  return Json::Value();
}

template<>
Json::Value convertJson<int>(const int& object) {
  return Json::Value(object);
}

template<>
Json::Value convertJson<uint>(const uint& object) {
  return Json::Value(object);
}

template<>
Json::Value convertJson<float>(const float& object) {
  return Json::Value(object);
}

template<>
Json::Value convertJson<double>(const double& object) {
  return Json::Value(object);
}

template<>
Json::Value convertJson<std::string>(const std::string& object) {
  return Json::Value(object);
}

template<>
Json::Value convertJson<char*>(char* const& object) {
    if (object == nullptr) {
        return Json::Value("");
    }
    return Json::Value(object);
}

template<>
Json::Value convertJson<std::vector<std::string>>(const std::vector<std::string>& object) {
  Json::Value data;
  for (auto str : object) {
    data.append(str);
  }
  return data;
}

template<>
Json::Value convertJson<std::vector<int>>(const std::vector<int>& object) {
  Json::Value data;
  for (auto str : object) {
    data.append(str);
  }
  return data;
}

template<typename T, typename std::enable_if<PropertyTag<T>::hasProperty, int>::type>
T FromJson(const Json::Value& data) {
  T object;

  constexpr auto nbProperties = std::tuple_size<decltype(T::properties)>::value;
  
  for_sequence(std::make_index_sequence<nbProperties>{}, [&](auto i){
    constexpr auto property = std::get<i>(T::properties);
    using Type = typename decltype(property)::Type;
    if (data.isMember(property.name)) {
        object.*(property.member) = std::move(asAny<Type>(data[property.name]));
    }
  });

  return object;
}

template<typename T, typename std::enable_if<PropertyTag<T>::hasProperty, int>::type>
Json::Value ToJson(const T& object) {
  Json::Value data;
  constexpr auto nbProperties = std::tuple_size<decltype(T::properties)>::value;
  for_sequence(std::make_index_sequence<nbProperties>{}, [&](auto i){
    constexpr auto property = std::get<i>(T::properties);
    using Type = typename decltype(property)::Type;
    data[property.name] = std::move(convertJson<Type>(object.*(property.member)));
  });

  return data;
}
}

it bases on c++14.
I provide Json::ToJson() and Json::FromJson() two interface for serialization and deserialization.
But It just support some basic type, std::vector<std::string>, std::vector<int>, and customized struct or class.

for example, InnerS2 has tuple type member named properties. It can be serialized.

struct InnerS2 {
  std::string m1;

  constexpr static auto properties = std::make_tuple(
    Json::property(&InnerS2::m1, "m1")
  );
};

What about your ideas ?
I will seriously refer to your suggestions. thx.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

The issue supplies serializer.h and an InnerS2 example, but names no repository file or test. Review the proposed Json::ToJson and Json::FromJson interfaces against jsoncpp's Json::Value API, then define a concrete supported-type scope and acceptance tests before implementation.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
backend-api-design
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.