Custom converters allow ArduinoJson to support user-defined types. This page shows how we can write converters for STL containers.

I’ll probably include these converters in the library someday.

std::vector

The following class adds support for std::vector<T>. Of course, T itself has to be supported by ArduinoJson, either natively or through a custom converter.

namespace ArduinoJson {
template <typename T>
struct Converter<std::vector<T> > {
  static void toJson(const std::vector<T>& src, JsonVariant dst) {
    JsonArray array = dst.to<JsonArray>();
    for (T item : src)
      array.add(item);
  }

  static std::vector<T> fromJson(JsonVariantConst src) {
    std::vector<T> dst;
    for (T item : src.as<JsonArrayConst>())
      dst.push_back(item);
    return dst;
  }

  static bool checkJson(JsonVariantConst src) {
    JsonArrayConst array = src;
    bool result = array;
    for (JsonVariantConst item : array)
      result &= item.is<T>();
    return result;
  }
};
}  // namespace ArduinoJson

Thanks to this converter, you can now write thinks like this:

std::vector<int> v1 = {1, 2};
doc["values"] = v1;

if (doc["values"].is<std::vector<int> >()) {
  std::vector<int> v2 = doc["values"];
  // ...
}

The same technique works with std::list. If you’re a TMP wizard, you can write a generic implementation by leveraging the Enable template parameter of Converter.

std::array

For std::array, we need a different converter because:

  1. it doesn’t support the push_back() operation
  2. it has a fixed size, so checkJson() must check it

Here is a possible implementation:

namespace ArduinoJson {
template <typename T, size_t N>
struct Converter<std::array<T, N> > {
  static void toJson(const std::array<T, N>& src, JsonVariant dst) {
    JsonArray array = dst.to<JsonArray>();
    for (T item : src)
      array.add(item);
  }

  static std::array<T, N> fromJson(JsonVariantConst src) {
    std::array<T, N> dst;
    size_t idx = 0;
    for (T item : src.as<JsonArrayConst>())
      dst[idx++] = item;
    return dst;
  }

  static bool checkJson(JsonVariantConst src) {
    JsonArrayConst array = src;
    bool result = array;
    size_t size = 0;
    for (JsonVariantConst item : array) {
      result &= item.is<T>();
      size++;
    }
    return result && size == N;
  }
};
}  // namespace ArduinoJson

std::map

Here is the implementation for std::map<std::string, T>, you can use a similar implementation for std::unordered_map.

namespace ArduinoJson {
template <typename T>
struct Converter<std::map<std::string, T> > {
  static void toJson(const std::map<std::string, T>& src, JsonVariant dst) {
    JsonObject obj = dst.to<JsonObject>();
    for (const auto& item : src)
      obj[item.first] = item.second;
  }

  static std::map<std::string, T> fromJson(JsonVariantConst src) {
    std::map<std::string, T> dst;
    for (JsonPairConst item : src.as<JsonObjectConst>())
      dst[item.key().c_str()] = item.value().as<T>();
    return dst;
  }

  static bool checkJson(JsonVariantConst src) {
    JsonObjectConst obj = src;
    bool result = obj;
    for (JsonPairConst item : obj)
      result &= item.value().is<T>();
    return result;
  }
};
}  // namespace ArduinoJson