Skip to content

[Question] How do I parse JSON into custom types? #1669

Description

@rcdailey

Reviewing the documentation, I don't see a lot of helpful examples on more complex parsing scenarios. Really it seems like most of the documentation describes going from types to JSON, but I need to completely deserialize JSON data into C++ objects.

Here is the JSON data I'm working with:

{
  "campaigns": [{
      "name": "patt_coupon",
      "start_date": "2019-01-01",
      "end_date": "2019-12-31",
      "push": "pass.com.company.coupon.5dollar",
      "pull": [
        "pass.com.company.coupon",
        "pass.com.company.coupon_revised"
      ]
    },
    {
      "name": "loyalty",
      "start_date": "2019-01-01",
      "end_date": "2019-12-31",
      "push": "pass.com.company.loyalty.program1",
      "pull": [
        "pass.com.company.loyalty.program1"
      ]
    }
  ]
}

For the campaigns array, I want to parse each element into an array of custom objects:

#include <fstream>
#include <stdexcept>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <fmt/format.h>
#include <nlohmann/json.hpp>

using json = nlohmann::json;
namespace boost
{
   namespace gregorian
   {
      void from_json(json& j, boost::gregorian::date& d)
      {
         std::string dateValue;
         j.get_to(dateValue);
         d = boost::gregorian::from_string(dateValue);
      }
   }
}

class WalletCampaignConfiguration::WalletCampaign
{
public:
   WalletCampaign(json& config)
   {
      config.at("start_date").get_to(startDate);
   }

   boost::gregorian::date startDate, endDate;
   std::string pushPass;
   std::vector<std::string> pullPasses;
};

int main() {
   std::ifstream file{jsonPath}; // this points to the file containing the JSON above
   if (!file)
   {
      throw std::runtime_error{"Unable to open wallet config json: " + jsonPath.string()};
   }

   json config;
   file >> config;

   for (auto const& campaignJson : config.at("campaigns"))
   {
      m_campaigns.push_back(std::make_unique<WalletCampaign>(campaignJson));
   }

   auto const& c = *m_campaigns.at(0);
   std::cout << "start: " << c.startDate << "\n\n";
   std::cout << "end: " << c.endDate << "\n\n";
   std::cout << "push: " << c.pushPass << "\n\n";

   for (auto const& p : c.pullPasses)
   {
      std::cout << "pull: " << p << "\n\n";
   }
}

I'm compiling this using Visual Studio 2019 with C++17 enabled. The code above doesn't compile, with these errors:

1>E:\code\frontend\source\Core\Wallet\Source\Wallet\WalletCampaignConfiguration.cpp(47,30): error C2672:  'nlohmann::basic_json<std::map,std::vector,std::string,bool,int64_t,uint64_t,double,std::allocator,nlohmann::adl_serializer>::get_to': no matching overloaded function found
1>E:\code\frontend\source\Core\Wallet\Source\Wallet\WalletCampaignConfiguration.cpp(47,1): error C2783:  'ValueType &nlohmann::basic_json<std::map,std::vector,std::string,bool,int64_t,uint64_t,double,std::allocator,nlohmann::adl_serializer>::get_to(ValueType &) noexcept(<expr>) const': could not deduce template argument for '__formal'
1>E:\code\frontend\source\Core\External\json\include\nlohmann/json.hpp(2680): message :  see declaration of 'nlohmann::basic_json<std::map,std::vector,std::string,bool,int64_t,uint64_t,double,std::allocator,nlohmann::adl_serializer>::get_to'

I'm not sure why it doesn't compile. But I'm sure it has to do with something about how I'm trying to use the library. Can you give me an example of how to parse this JSON document in an object oriented way as I'm trying to do?

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

    kind: questionstate: stalethe issue has not been updated in a while and will be closed automatically soon unless it is updated

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions