Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
zpalmtree opened this issue Sep 30, 2018 · 5 comments
Closed

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

zpalmtree opened this issue Sep 30, 2018 · 5 comments
Labels
solution: proposed fix a fix for the issue has been proposed and waits for confirmation

Comments

@zpalmtree
Copy link

zpalmtree commented Sep 30, 2018

  • 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

@nlohmann
Copy link
Owner

nlohmann commented Oct 1, 2018

Thanks for providing such a detailed issue.

I tried to reproduce it, but had some strange observation:

  • With Apple LLVM version 10.0.0 (clang-1000.10.43.1) and Xcode 10.0, I can compile and run your code without issues with version 3.2.0 of the library.
  • With the develop version, I have a compilation error in line j.at("keyImages").get<std::unordered_set<PublicKey>>();: main.cpp:44:37: No matching member function for call to 'get'

This is really strange, and I fear the only person who can help here would be @theodelrieu.

@nlohmann nlohmann added the state: help needed the issue needs help to proceed label Oct 1, 2018
@nlohmann
Copy link
Owner

@theodelrieu Do you have any idea on this?

@theodelrieu
Copy link
Contributor

I'm not sure I understand the exact issue, it seems to me that you could do the following:

void from_json(json const& j, PublicKey& k) {
  podFromHex(k.data, j.get<std::string>());
}

Have I missed something?

@theodelrieu
Copy link
Contributor

Also, note that you must have from_json(PublicKey) defined before from_json(Wallet)

@zpalmtree
Copy link
Author

Thank you, that worked! I was not aware I could just get the raw string from the json, I figured I needed a way to index it as it was all one large object.

@nlohmann nlohmann added solution: proposed fix a fix for the issue has been proposed and waits for confirmation and removed state: help needed the issue needs help to proceed labels Oct 16, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
solution: proposed fix a fix for the issue has been proposed and waits for confirmation
Projects
None yet
Development

No branches or pull requests

3 participants