Skip to content

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

@zpalmtree

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

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