reflective-rapidjson/README.md

190 lines
6.8 KiB
Markdown
Raw Normal View History

2017-10-28 18:24:12 +02:00
# Reflective RapidJSON
2017-10-24 18:00:51 +02:00
The main goal of this project is to provide a code generator for serializing/deserializing C++ objects to/from JSON
using Clang and RapidJSON.
However, extending the generator to generate code for other applications of reflection or to provide generic
reflection functionallity would be possible as well.
This repository also contains a small, additional header to use RapidJSON with Boost.Hana. This allows to serialize
or dezerialize simple data structures using the `BOOST_HANA_DEFINE_STRUCT` macro rather than requiring the code
generator.
2017-10-24 18:00:51 +02:00
2017-10-29 23:46:11 +01:00
## Supported datatypes
The following table shows the mapping of supported C++ types to supported JSON types:
| C++ type | JSON type |
| ---------------------------------------- |:---------:|
| custom structures/classes | object |
| bool | true/false|
| signed and unsigned integral types | number |
| float and double | number |
| enum and enum class | number |
| std::string | string |
| const char * | string |
| iteratables (std::vector, std::list, ...)| array |
| std::tuple | array |
### Remarks
* `const char *` is only supported for serialization.
* Enums are only supported for serialization.
* For deserialization, iteratables must provide an `emplace_back` method. So deserialization of eg. `std::forward_list`
is currently not supported.
* Using pointers is not supported yet.
* The JSON type `null` is not supported yet.
2017-10-24 18:00:51 +02:00
## Usage
This example shows how the library can be used to make a `struct` serializable:
```
#include <reflective-rapidjson/json/serializable.h>
2017-10-25 20:03:58 +02:00
// define structures, eg.
struct TestObject : public JsonSerializable<TestObject> {
2017-10-25 20:03:58 +02:00
int number;
double number2;
vector<int> numbers;
string text;
bool boolean;
};
struct NestingObject : public JsonSerializable<NestingObject> {
2017-10-25 20:03:58 +02:00
string name;
TestObject testObj;
};
struct NestingArray : public JsonSerializable<NestingArray> {
2017-10-25 20:03:58 +02:00
string name;
vector<TestObject> testObjects;
};
// serialize to JSON
NestingArray obj{ ... };
cout << "JSON: " << obj.toJson().GetString();
// deserialize from JSON
const auto obj = NestingArray::fromJson(...);
// in exactly one of the project's translation units
#include "reflection/code-defining-structs.h"
2017-10-24 18:00:51 +02:00
```
2017-10-25 20:03:58 +02:00
Note that the header included at the bottom must be generated by invoking the code generator appropriately, eg.:
2017-10-24 18:00:51 +02:00
```
2017-10-25 20:03:58 +02:00
reflective_rapidjson_generator -i "$srcdir/code-defining-structs.cpp" -o "$builddir/reflection/code-defining-structs.h"
2017-10-24 18:00:51 +02:00
```
It is possible to use the provided CMake macro to automate this task:
```
2017-10-25 20:03:58 +02:00
find_package(reflective-rapidjson REQUIRED)
list(APPEND CMAKE_MODULE_PATH ${REFLECTIVE_RAPIDJSON_MODULE_DIRS})
include(ReflectionGenerator)
add_reflection_generator_invocation(
INPUT_FILES code-defining-structs.cpp
GENERATORS json
OUTPUT_LISTS LIST_OF_GENERATED_HEADERS
)
2017-10-24 18:00:51 +02:00
```
2017-10-25 20:03:58 +02:00
This will produce the file `code-defining-structs.h` in the directory `reflection` in the current build directory. So
make sure the current build directory is added to the include directories of your target. The default output directory can
also be overridden by passing `OUTPUT_DIRECTORY custom/directory` to the arguments.
It is possible to specify multiple input files at once. A separate output file is generated for each input. The output files
will always have the extension "`.h`", independently of the extension of the input file.
The full paths of the generated files are also appended to the variable `LIST_OF_GENERATED_HEADERS` which then can be added
to the sources of your target. Of course this can be skipped if not required/wanted.
### Using Boost.Hana instead of the code generator
The same example as above. However, this time Boost.Hana is used - so it doesn't require invoking the generator.
2017-10-24 18:00:51 +02:00
```
#include "<reflective-rapidjson/json/serializable-boosthana.h>
2017-10-25 20:03:58 +02:00
// define structures using BOOST_HANA_DEFINE_STRUCT, eg.
struct TestObject : public JsonSerializable<TestObject> {
2017-10-25 20:03:58 +02:00
BOOST_HANA_DEFINE_STRUCT(TestObject,
(int, number),
(double, number2),
(vector<int>, numbers),
(string, text),
(bool, boolean)
);
};
struct NestingObject : public JsonSerializable<NestingObject> {
2017-10-25 20:03:58 +02:00
BOOST_HANA_DEFINE_STRUCT(NestingObject,
(string, name),
(TestObject, testObj)
);
};
struct NestingArray : public JsonSerializable<NestingArray> {
2017-10-25 20:03:58 +02:00
BOOST_HANA_DEFINE_STRUCT(NestingArray,
(string, name),
(vector<TestObject>, testObjects)
);
};
// serialize to JSON
NestingArray obj{ ... };
cout << "JSON: " << obj.toJson().GetString();
// deserialize from JSON
const auto obj = NestingArray::fromJson(...);
2017-10-24 18:00:51 +02:00
```
So beside the `BOOST_HANA_DEFINE_STRUCT` macro, the usage remains the same.
2017-10-25 20:03:58 +02:00
2017-10-24 18:00:51 +02:00
## Install instructions
### Dependencies
* C++ compiler and standard library supporting at least C++14
* the CMake build system
* LibTooling from Clang for the code generator
* RapidJSON for JSON (de)serialization
2017-10-25 19:25:27 +02:00
* Boost.Hana for using `BOOST_HANA_DEFINE_STRUCT` instead of code generator
2017-10-24 18:00:51 +02:00
* `c++utilities` for various helper functions
Optional:
* CppUnit for building and running the tests
* Doxygen for generating API documentation
* Graphviz for diagrams in the API documentation
2017-10-28 22:52:31 +02:00
Note that Reflective RapidJSON itself and none of these dependencies are required at runtime by an application
which makes use of Reflective RapidJSON.
2017-10-24 18:00:51 +02:00
### How to build
Install all required dependencies and ensure the CMake script finds them. It is possible to build `c++utilities`
2017-10-28 18:24:12 +02:00
together with `reflective-rapidjson` to simplify the build process. The following build script makes use of this.
To use system `c++utilities`, just skip any lines with "`c++utilities`" in the following examples.
2017-10-24 18:00:51 +02:00
2017-10-28 18:24:12 +02:00
Get sources, eg. using Git:
2017-10-24 18:00:51 +02:00
```
2017-10-28 18:24:12 +02:00
cd $SOURCES
git clone https://github.com/Martchus/cpp-utilities.git c++utilities
git clone https://github.com/Martchus/reflective-rapidjson.git
2017-10-24 18:00:51 +02:00
```
2017-10-28 18:24:12 +02:00
If you don't want to build the development version, just checkout the desired version tag.
Here is an example for building with CMake and GNU Make:
```
cd $BUILD_DIR
# generate Makefile
cmake \
-DCMAKE_BUILD_TYPE:STRING=Release \
-DCMAKE_INSTALL_PREFIX:PATH="/final/install/prefix" \
-DBUNDLED_CPP_UTILITIES_PATH:PATH="$SOURCES/c++utilities" \
"$SOURCES/reflective-rapidjson"
# build library and generators
make
2017-10-28 22:52:31 +02:00
# build and run tests (optional, requires CppUnit)
2017-10-28 18:24:12 +02:00
make check
2017-10-28 22:52:31 +02:00
# build tests but do not run them (optional, requires CppUnit)
make tests
# generate API documentation (optional, reqquires Doxygen)
2017-10-28 18:24:12 +02:00
make apidoc
# install header files, libraries and generator
make install DESTDIR="/temporary/install/location"
```
Add eg. `-j$(nproc)` to `make` arguments for using all cores.