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

std::string and std::wstring to_json #1592

Closed
zivsha opened this issue Apr 30, 2019 · 10 comments
Closed

std::string and std::wstring to_json #1592

zivsha opened this issue Apr 30, 2019 · 10 comments
Labels
kind: question solution: proposed fix a fix for the issue has been proposed and waits for confirmation

Comments

@zivsha
Copy link

zivsha commented Apr 30, 2019

Q1: Glorified string

I have a glorified string class which I want json to treat as a value object (specifically as a string). For example:

class Guid {
public:
    std::string str;
    Guid() = default;
    //...
};

And another class that holds a Guid and should be serialized to json, so I want to be able to do:

void to_json(nlohmann::json& j, const Person& p) {
    j = nlohmann::json{ 
        { "guid", p.guid },  //Compiler error
        { "name", p.name }
    };
}

I want the end result of Person::to_json to be:

{
  guid : "0000-....-0000",
  name : "Name"
}

I tried adding a to_json for theGuid but since I don't want another object level inside the guid key, I wrote:

void to_json(nlohmann::json& j, const Guid& g) {
    j = nlohmann::json{ g.str) };
}

But this returned the guid as array of 1 element:

{
  guid : ["0000-....-0000"],
  name : "Name"
}

How can I make it return just a single string object?

Q2: custom std::wstring to json

My application uses std::wstring all over, so I have a to_utf8 function which returns a std::string that can be stored in the json object. At the moment whenever I implement a to_json function for an object that holds a wide string, I have to remember to call to_utf8 otherwise the json object will be invalid or throw when calling dump.

Is there a way to override the way the library serializes std::wstring so that I can add a call there to to_utf8 and then remove this call from all other places? something like:

void to_json(nlohmann::json& j, const std::wstring& s) {
   j = nlohmann::json{ to_utf8(s) };
}

The above is not even called (maybe due to ADL?) but either way I assume it will suffer from the same issue as question 1 (will be output as an array of single object)

Thanks.

@zivsha
Copy link
Author

zivsha commented Apr 30, 2019

Hah I figured the answer to the first question, just assign the string to the json.
Is this expected behavior when using this code?

void to_json(nlohmann::json& j, const Guid& g) {
    j = g.str;
}

@zivsha
Copy link
Author

zivsha commented Apr 30, 2019

I was able to solve the second question as well, it really was ADL 😃

Here's how:

namespace nlohmann {
    template <>
    struct adl_serializer<std::wstring> {
        static void to_json(json& j, const std::wstring& str) {
            j = to_utf8(str);
        }

        static void from_json(const json& j, std::wstring& str) {
            str = from_utf8(j.get<std::string>());
        }
    };
}

@zivsha zivsha closed this as completed Apr 30, 2019
@nlohmann nlohmann added the solution: proposed fix a fix for the issue has been proposed and waits for confirmation label Jun 2, 2019
@lipasite
Copy link

@zivsha Can you show the code of to_utf8 and from from_utf8 functions?

@zivsha
Copy link
Author

zivsha commented Feb 14, 2021

I used WideCharToMultiByte

@eagle-dot
Copy link

My application needs to write wstring ( wide string ) into a json file. The Wstring can contain Japanese charaters, Hebrew, Korean, Chinese character. We want the json file to be human readable - for example : 車B1234 こんにちは .

However, Json object does not accept wstring at all ,neither it can dump - serialize to wide string

json j_body;
wstring my_data = L" 車B1234 こんにちは";
j_body DATA] = my_data; // Error1
wstring J_string = j_body,dump(1); //Error2

Error 1:
error: no match for ‘operator=’ (operand types are ‘nlohmann::basic_json<>::value_type {aka nlohmann::basic_json<>}’ and ‘const wchar_t*’)
j_body DATA] = my_data;

Error2
error: conversion from ‘nlohmann::basic_json<>::string_t {aka std::__cxx11::basic_string}’ to non-scalar type ‘std::__cxx11::wstring {aka std::__cxx11::basic_string<wchar_t>}’ requested
wstring j_string =j_header.dump(1);

Any advice ?

@nlohmann
Copy link
Owner

This library does not support std::wstring. Please convert the std::wstring to a UTF-8-encoded std::string first.

@eagle-dot
Copy link

eagle-dot commented Jul 26, 2021

@nlohmann Thanks for the tip, and it is working now.

I share my source code for others to use it freely

#include    <stream>
#include    <locale>
#include   <codecvt>
#include "json.hpp"

//    #include <string>
//   #include <locale>
//  #include <codecvt>
//  3 include files are : string, locale, codecvt.  somehow, the system does not display them.  you can manually copy source code  into your program.

using namespace =std;
using json = nlohmann::json;

int main (int argc, char* argv[])
{

     json j_body;
     using convert_typeX =std::codecvt_utf8<wchar_t>; 
     wstring my_data = L" 車B1234 こんにちは"; 
     wstring_convert<std::codecvt_utf8<wchar_t>> utf8_conv;
     j_body [DATA] = utf8_conv.to_bytes(my_data) ;
     string address ("2021 Downtown,  Houston, TX, USA");
     j_body [ADDRESS] = address;
     j_body.dump(1);    //display json file 

     return 0;
}

@nlohmann
Copy link
Owner

nlohmann commented Jul 29, 2021

Thanks a lot! I will add this code do the documentation.

Update: https://json.nlohmann.me/home/faq/#wide-string-handling

@zivsha
Copy link
Author

zivsha commented Aug 2, 2021

    wstring my_data = L" 車B1234 こんにちは"; 
    wstring_convert<std::codecvt_utf8<wchar_t>> utf8_conv;
    j_body [DATA] = utf8_conv.to_bytes(my_data) ;
    string address ("2021 Downtown,  Houston, TX, **USA");**

Note that wstring_convert<std::codecvt_utf8<>> is deprecated starting C++17

@nlohmann
Copy link
Owner

nlohmann commented Aug 2, 2021

Thanks for noting. As long as there is no new standard way to do it, I just leave the documentation as is.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind: question solution: proposed fix a fix for the issue has been proposed and waits for confirmation
Projects
None yet
Development

No branches or pull requests

4 participants