๐ก๋ณธ ๋ฌธ์๋ 'OpenSource ๋ฏ์ด๋ณด๊ธฐ'๋ผ๋ ํ๋ก์ ํธ์ ์ผํ์ผ๋ก.
nlohmann/json๋ผ๋ c++ json library๋ฅผ ์ค์น, ์คํ ๋ฑ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ๊ณผ ๋๋ถ์ด, library ๋ด ๊ตฌ์กฐ, ์์ค ๋ถ์ ๋ฐ ํจํด ๋ถ์๊น์ง ๋ค๋ฃฐ ์์ ์ด๋ ํด๋น ์คํ์์ค์ ๊ด์ฌ์ด ์๋ค๋ฉด ๋ด๋๊ธธ ๊ถ์ฅํฉ๋๋ค.
1. ์คํ์์ค์ ๋ชฉ์
1.1 'nlohmann/json'์ ๋ํ์ฌ.
- C++ Json library
- modern C++์ operation์ ์ง์
- nlohmann/json.hpp ํ๋์ ํค๋ํ์ผ๋ก ์ฌ์ฉ๊ฐ๋ฅ
- That's it. No library, no subproject, no dependencies, no complex build system.
- C++ data types:
- std::string for strings
- int64_t, uint64_t or double for numbers
- std::map for objects
- std::vector for arrays
- bool for Booleans.
- you can template the generalized class basic_json to your needs.
- Json library ์ค ๋น ๋ฅธ ํธ์ ์ํจ
1.2 'nlohmann/json' ์ถ๊ฐ ์ ๋ณด
- Git: https://github.com/nlohmann/json
- Docs: https://json.nlohmann.me/
- Lisence: MIT License: Copyright © 2013-2022 Niels Lohmann
2. ํ๊ฒฝ ๊ตฌ์ถ
2.1 ํ๊ฒฝ ๊ตฌ์ถ: CMake (FetchContent)
include(FetchContent)
FetchContent_Declare(
json
GIT_REPOSITORY https://github.com/nlohmann/json.git
GIT_TAG v3.10.5
)
FetchContent_MakeAvailable(json)
target_link_libraries(${PROJECT_NAME} PRIVATE nlohmann_json::nlohmann_json)
2.2 ๊ฐ๋จํ ์ฌ์ฉ (Generate Json)
2.2.1 Json ์์ฑ(like jsoncpp)
// create an empty structure (null)
json j;
// add a number that is stored as double (note the implicit conversion of j to an object)
j["pi"] = 3.141;
// add another null object by passing nullptr
j["nothing"] = nullptr;
// add an object inside the object
j["answer"]["everything"] = 42;
// add an array that is stored as std::vector (using an initializer list)
j["list"] = { 1, 0, 2 };
// add another object (using an initializer list of pairs)
j["object"] = { {"currency", "USD"}, {"value", 42.99} };
2.2.2 Jsonํ์ผ๊ณผ ์ ์ฌ
// instead, you could also write (which looks very similar to the JSON above)
json j2 = {
{"pi", 3.141},
{"nothing", nullptr},
{"answer", {
{"everything", 42}
}},
{"list", {1, 0, 2}},
{"object", {
{"currency", "USD"},
{"value", 42.99}
}}
};
2.2.3 Jsonํ์ผ๊ณผ ๋์ผ
You can create a JSON value (deserialization) by appending _json to a string literal:
// create object from string literal
json j = "{ \"happy\": true, \"pi\": 3.141 }"_json;
// or even nicer with a raw string literal
auto j2 = R"(
{
"happy": true,
"pi": 3.141
}
)"_json;
2.3 ๊ฐ๋จํ ์ฌ์ฉ (Parsing Json)
2.3.1 Json Parsing
// parse explicitly
auto j3 = json::parse(R"({"happy": true, "pi": 3.141})");
2.3.2 Json To String
// explicit conversion to string
std::string s = j.dump(); // {"happy":true,"pi":3.141}
// serialization with pretty printing
// pass in the amount of spaces to indent
std::cout << j.dump(4) << std::endl;
// {
// "happy": true,
// "pi": 3.141
// }
2.3.3 Retrieve Json value
// retrieve the string value
auto cpp_string = j_value.get<std::string>();
// retrieve the string value (alternative when a variable already exists)
std::string cpp_string2;
j_value.get_to(cpp_string2);
// retrieve another value
auto cpp_int = j_value["int value"].get<int>();
auto cpp_int64 = j_value["int64 value"].get<int64_t>();
auto cpp_double = j_value["double value"].get<double>();
auto cpp_object = j_value["object value"].get<std::map>();
auto cpp_array = j_value["array value"].get<std::vector>();
// use function at() to access the object values rather than operator[].
// In case a key does not exist, at throws an exception that you can handle,
// whereas operator[] exhibits undefined behavior.
auto cpp_uint64 = j_value.at("uint64 value").get<uint64_t>();
// Good data handling: conditional number conversion
if (cpp_int.is_number_integer()) { auto cpp_int64 = j_value["int64 value"].get<int64_t>(); }
number type | default type | possible values |
signed integers | std::int64_t | std::int32_t, std::int16_t, etc. |
unsigned integers | std::uint64_t | std::uint32_t, std::uint16_t, etc. |
floating-point | double | float, long double |
- The type for signed integers must be convertible from long long. The type for floating-point numbers is used in case of overflow.
- The type for unsigned integers must be convertible from unsigned long long. The type for floating-point numbers is used in case of overflow.
+ JsonCpp get() method (in nlohmann::json)
// JsonCpp
auto two = j_object.value("two", 2).get();
// i) nlohmann::json value (Implemented by try, catch)
auto two = j_object.value("two", 2).get<int32_t>();
// ii) nlohmann::json try, catch
try {
auto two = j_object.at("two").get<int32_t>();
} catch(){
auto two = 2
}
// iii) nlohmann::json find
if (j_object.find("two") == j_object.end()) {
j_object["two"] = 2;
}
auto two = j_object["two"].get<int32_t>();
๋จ, nlohmannjson.value("key", "default value")๋ฅผ ์ธ ๋ ์ฃผ์ํด์ผํ ์ฌํญ์ด ์์ต๋๋ค.
- json struct์ ์๋ฌด ๊ฐ์ด ์์ผ๋ฉด ํน์ key ๊ฐ์ ๋ฝ์ผ๋ ค๋ ์๋๋ง์ผ๋ก ๋ค์๊ณผ ๊ฐ์ ์๋ฌ๊ฐ ๋ฐ์ํฉ๋๋ค.
- [Error Message]: C++ exception with description "[json.exception.type_error.306] cannot use value() with null" thrown in the test body.
2.4 ๊ฐ๋จํ ์ฌ์ฉ (Arbitrary types conversions)
2.4.1 Using to_json, from_json: struct to json convertor
When calling the json constructor with your type, your custom to_json method will be automatically called.
Likewise, when calling get<your_type>() or get_to(your_type&), the from_json method will be called.
using nlohmann::json;
namespace ns {
void to_json(json& j, const person& p) {
j = json{{"name", p.name}, {"address", p.address}, {"age", p.age}};
}
void from_json(const json& j, person& p) {
j.at("name").get_to(p.name);
j.at("address").get_to(p.address);
j.at("age").get_to(p.age);
}
} // namespace ns
// create a person
ns::person p {"Ned Flanders", "744 Evergreen Terrace", 60};
// conversion: person -> json
json j = p;
std::cout << j << std::endl;
// {"address":"744 Evergreen Terrace","age":60,"name":"Ned Flanders"}
// conversion: json -> person
auto p2 = j.get<ns::person>();
// that's it
assert(p == p2);
2.4.2 Macros: Simplyfy to_json, from_json
namespace ns {
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person, name, address, age)
}
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(name, member1, member2, ...) is to be defined inside the namespace of the class/struct to create code for.
namespace ns {
class address {
private:
std::string street;
int housenumber;
int postcode;
public:
NLOHMANN_DEFINE_TYPE_INTRUSIVE(address, street, housenumber, postcode)
};
}
NLOHMANN_DEFINE_TYPE_INTRUSIVE(name, member1, member2, ...) is to be defined inside the class/struct to create code for. This macro can also access private members.
2.4.3 Convert third-party types: char*, char[], union, ...
template <typename T>
struct adl_serializer {
static void to_json(json& j, const T& value) {
// calls the "to_json" method in T's namespace
}
static void from_json(const json& j, T& value) {
// same thing, but with the "from_json" method
}
};
์ฐธ๊ณ : https://github.com/nlohmann/json#how-do-i-convert-third-party-types
+ Specializing enum conversion
// example enum type declaration
enum TaskState {
TS_STOPPED,
TS_RUNNING,
TS_INVALID=-1,
};
// map TaskState values to JSON as strings
NLOHMANN_JSON_SERIALIZE_ENUM( TaskState, {
{TS_INVALID, nullptr},
{TS_STOPPED, "stopped"},
{TS_RUNNING, "running"}
})
usage:
// enum to JSON as string
json j = TS_STOPPED;
assert(j == "stopped");
// json string to enum
json j3 = "running";
assert(j3.get<TaskState>() == TS_RUNNING);
// undefined json value to enum (where the first map entry above is the default)
json jPi = 3.14;
assert(jPi.get<TaskState>() == TS_INVALID );
+ json visualization
jsonvisio: https://jsonvisio.com/editor
์ฐธ๊ณ
- [Github] nlohmann/json: https://github.com/nlohmann/json
- [Official Docs] JSON for Modern C++: https://json.nlohmann.me/
- [Official Docs] nlohmann/json value example: https://json.nlohmann.me/api/basic_json/value/#examples
- [Official Docs] Number Handling: https://json.nlohmann.me/features/types/number_handling/#number-comparison
- [nlohmann] nlohmann/json community: https://gitter.im/nlohmann/json?at=5c8388748f294b134a127674
- [stackoverflow] How do i read/write JSON with c++?: https://stackoverflow.com/questions/70684671/how-do-i-read-write-json-with-c
- [blog] tutorial to use nlohmann json for serializing data with modern cpp: https://kezunlin.me/post/f3c3eb8/
- [blog] Nlohmann Json ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ํ
- https://json.nlohmann.me/integration/cmake/
- [Git issue] Change JsonCpp to nlohmann/json: https://github.com/drogonframework/drogon/issues/249
- [KeZunLin] to_json, from_json: https://kezunlin.me/post/f3c3eb8/