Skip to content

Parsing JSON Array where members have no key, using custom types #1267

Description

@zpalmtree
  • What is the issue you have?
    I'm trying to reduce the level of nesting in my output JSON. I can do this fine by converting my type directly to a string, rather than giving the single member variable a name, for example:
void to_json(json &j, const PublicKey &s)
{
    /* .data is an array of uint8_t, podToHex converts to a hex string */
    j = Common::podToHex(s.data);
}

instead of

void to_json(json &j, const PublicKey &s)
{
    j = {"publicKey", Common::podToHex(s.data)};
}

This works fine, and in my usage this function gets used to convert a std::unordered_set to json. Here's an example json output I get:

"keyImages": [
       "0682b576d89456a958c496a5e053deddf96645b3a9a5f371e160e0ce66d98ecb",
       "145c1153ad0040a3bf24b0e96bd8c39e216cce785782fd1d7fec67ad483fbb4b",
       "8285716e53853663ba1fa02d977a10181543541e2f13bba983994e98f45cfbee",
       "f436604c007c4fca61a7d5ad474051ec2d66cd75856ef209b02106ba9bd10a36",
       "6ab7fb46e729fc707966776203d955e6afa90f527aae7bed5cda121d782fd9ee",
       "bf2c60b78877115bff86b90d6c5d689832ec4697ef8984f44f2cfa6dc5f3d90d"
],

Now however, I'm not sure how to convert this JSON back into my type. The type is a std::unordered_set. Previously, I was giving a data name to each array element, so my from_json looked like -

void from_json(const json &j, PublicKey &s)
{
    std::string hash = j.at("publicKey").get<std::string>();
    /* Converts from string to uint8_t array */
    Common::podFromHex(hash, s.data);
}

However, this cannot work if we are not storing the key name. How can we implement our from_json function without having a key name to at()?

  • Please describe the steps to reproduce the issue. Can you provide a small but working code example?
#include "json.hpp"
#include <unordered_set>

using nlohmann::json;

void podFromHex(const uint8_t *data, std::string hash)
{
    /* Completely horrible simple implementation for example purposes */
    data = reinterpret_cast<const uint8_t *>(hash.c_str());
}

struct PublicKey
{
    uint8_t data[32];

    inline bool operator==(const PublicKey &other) const
    {
        return std::memcmp(this->data, other.data, sizeof(PublicKey::data)) == 0;
    }
};

namespace std
{
    template<>
    struct hash<PublicKey>
    {
        size_t operator()(const PublicKey &p) const
        {
            return reinterpret_cast<const size_t &>(p);
        }
    };
}

struct Wallet
{
    std::unordered_set<PublicKey> keyImages;
    uint64_t balance;
};

void from_json(const json &j, Wallet &w)
{
    w.balance = j.at("balance").get<uint64_t>();
    w.keyImages = j.at("keyImages").get<std::unordered_set<PublicKey>>();
}

void from_json(const json &j, PublicKey &p)
{
    /* What should this be?
    std::string hash = j.at("???").get<std::string>();
    */

    std::string hash;
    podFromHex(p.data, hash);
}

int main()
{
    json j = {
        {"balance", 100},
        {"keyImages", {
            "0682b576d89456a958c496a5e053deddf96645b3a9a5f371e160e0ce66d98ecb",
            "145c1153ad0040a3bf24b0e96bd8c39e216cce785782fd1d7fec67ad483fbb4b",
            "8285716e53853663ba1fa02d977a10181543541e2f13bba983994e98f45cfbee"
        }}
    };

    Wallet w = j;
}
  • What is the expected behavior?
    Am able to convert json to custom type

  • And what is the actual behavior instead?

terminate called after throwing an instance of 'nlohmann::detail::type_error'
  what():  [json.exception.type_error.304] cannot use at() with string
  • Which compiler and operating system are you using? Is it a supported compiler?
    Compiler: g++ 8.2.1
    OS: Linux 4.18.9

  • Did you use a released version of the library or the version from the develop branch?
    Using the released version, v3.2.0

  • If you experience a compilation error: can you compile and run the unit tests?
    N/A

edit - Of course I could just use a function and loop through the data, but I'd prefer a solution where I don't need to have a function for each standard container type which already has support built in

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    solution: proposed fixa fix for the issue has been proposed and waits for confirmation

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions