json/README.md

103 lines
3.6 KiB
Markdown
Raw Normal View History

2023-08-05 00:56:14 +03:00
## Purpose
2015-02-19 00:28:56 +03:00
2023-08-05 00:56:14 +03:00
Suppose that your application has a complex configuration and:
* that configuration is represented as a set of JSON files
* the files are supposed to be edited by the end-users
* the application on its own provides/dumps only a "default" set of files
somehow annotating the dumped JSON makes much more sense than maintaining a separate documentation
for the allowed values and expected keys, which will get out of date on the nearest occasion.
2019-12-01 12:23:24 +03:00
2023-08-05 00:56:14 +03:00
As per the [original JSON's RFC](https://datatracker.ietf.org/doc/html/rfc8259) comments are not allowed in JSON. But, knowing that the world
is not ideal, [nlohmann's JSON library](https://github.com/nlohmann/json) does support parsing JSON files with so-called "comments", encoded as follows:
2016-12-11 21:42:36 +03:00
```
2015-02-19 00:28:56 +03:00
{
2023-08-05 00:56:14 +03:00
/* this is a comment */
"property_1": 5
}
2015-02-19 00:28:56 +03:00
```
2023-08-05 00:56:14 +03:00
A specific overload of the `parse` method has to be called, as per [this](https://json.nlohmann.me/features/comments/) part of the reference:
2016-06-22 23:20:55 +03:00
2017-01-17 01:23:06 +03:00
```
2023-08-05 00:56:14 +03:00
json j = json::parse(s,
/* callback */ nullptr,
/* allow exceptions */ true,
/* ignore_comments */ true);
2017-01-17 01:23:06 +03:00
```
2023-08-05 00:56:14 +03:00
(so, more specifically, the library allows ignoring them)
2017-08-15 21:49:18 +03:00
2023-08-05 00:56:14 +03:00
However, the library does not allow for annotating (adding the comments) when serializing your custom classes or structures. Best you could
possibly do is post-process the dumped string or file through raw string processing, which is error-prone and problematic.
2020-06-29 14:43:06 +03:00
2023-08-05 00:56:14 +03:00
This fork of the [nlohmann's JSON library](https://github.com/nlohmann/json) adds a possibility to add annotations (known at compile-time) to your classes and structures. I'll try to keep the fork up to date with the original repository, potentially "shadowing" the releases in the future as well[^1].
2020-06-29 14:43:06 +03:00
2023-08-05 00:56:14 +03:00
## How to use
2020-06-29 14:43:06 +03:00
2023-08-05 00:56:14 +03:00
Currently, the extension applies exclusively[^2] to [`NLOHMANN_DEFINE_TYPE_INTRUSIVE` macro](https://github.com/nlohmann/json#simplify-your-life-with-macros):
2020-07-14 16:36:06 +03:00
2020-06-29 14:43:06 +03:00
```
2023-08-05 00:56:14 +03:00
class ExampleClass {
private:
int property1{1};
double property2{2.5};
std::string property3{"test"};
std::map<std::string, int> property4{{"x", 1}, {"y", 2}};
std::vector<double> property5{1.5, 5.4, 3.2};
public:
ExampleClass() = default;
2017-01-17 01:23:06 +03:00
2023-08-05 00:56:14 +03:00
NLOHMANN_DEFINE_TYPE_INTRUSIVE_ANNOTATED(ExampleClass, property1, "comment两两",
property2, "multiline\ncomment2",
property3, "comment3",
property4, "comment4",
property5, "comment5");
2017-01-17 01:23:06 +03:00
};
```
2023-08-05 00:56:14 +03:00
Dumping is as simple as that:
2017-01-17 01:23:06 +03:00
```
2023-08-05 00:56:14 +03:00
int main() {
ExampleClass ec;
std::ofstream example_file;
example_file.open("example_1.json");
2017-01-17 01:23:06 +03:00
2023-08-05 00:56:14 +03:00
nlohmann::json j = ec;
example_file << j.dump_annotated<ExampleClass>(4) << std::endl;
// instead of the original:
// example_file << j.dump(4) << std::endl;
2018-02-24 02:29:42 +03:00
2023-08-05 00:56:14 +03:00
return 0;
2017-01-17 01:23:06 +03:00
}
```
2023-08-05 00:59:29 +03:00
This is then going to produce a JSON file like this:
2023-08-05 00:59:29 +03:00
```
{
/* comment两两 */
"property1": 1,
/* multiline */
/* comment2 */
"property2": 2.5,
/* comment3 */
"property3": "test",
/* comment4 */
"property4": {
"x": 1,
"y": 2
},
/* comment5 */
"property5": [
1.5,
5.4,
3.2
]
}
```
2021-01-27 16:34:10 +03:00
2023-08-05 00:59:29 +03:00
[^1]: Tried creating a pull request in the original repository, but I doubt it's ever going to be considered.
[^2]: If you look closely at the new macro, it's relatively easy to figure out how to actually *avoid* using the macro, but I need to document that to make it officially supported.