You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

108 lines
4.6 KiB

# `libjsonpbparse`
This library provides functions to parse a JSON file to a structured Protobuf
message.
At this time of writing, `libprotobuf-cpp-full` is at version 3.0.0-beta, and
unknown fields in a JSON file cannot be ignored. Do **NOT** use this library in
vendor / recovery until `libprotobuf-cpp-full` is updated.
## Using `libjsoncpp` in parser code
Since `libjsonpbparse` cannot be used in vendor / recovery processes yet,
`libjsoncpp` is used instead. However, there are notable differences in the
logic of `libjsoncpp` and `libprotobuf` when parsing JSON files.
- There are no implicit string to integer conversion in `libjsoncpp`. Hence:
- If the Protobuf schema uses 64-bit integers (`(s|fixed|u|)int64`):
- The JSON file must use strings (to pass tests in `libjsonpbverify`)
- Parser code (that uses `libjsoncpp`) must explicitly convert strings to
integers. Example:
```c++
strtoull(value.asString(), 0, 10)
```
- If the Protobuf schema uses special floating point values:
- The JSON file must use strings (e.g. `"NaN"`, `"Infinity"`, `"-Infinity"`)
- Parser code must explicitly handle these cases. Example:
```c++
double d;
if (value.isNumeric()) {
d = value.asDouble();
} else {
auto&& s = value.asString();
if (s == "NaN") d = std::numeric_limits<double>::quiet_NaN();
else if (s == "Infinity") d = std::numeric_limits<double>::infinity();
else if (s == "-Infinity") d = -std::numeric_limits<double>::infinity();
}
```
- `libprotobuf` accepts either `lowerCamelCase` (or `json_name` option if it is
defined) or the original field name as keys in the input JSON file.
The test in `libjsonpbverify` explicitly check this case to avoid ambiguity;
only the original field name (or `json_name` option if it is defined) can be
used.
Once `libprotobuf` in the source tree is updated to a higher version and
`libjsonpbparse` is updated to ignore unknown fields in JSON files, all parsing
code must be converted to use `libjsonpbparse` for consistency.
# `libjsonpbverify`
This library provides functions and tests to examine a JSON file and validate
it against a Protobuf message definition.
In addition to a validity check that `libprotobuf` can convert the JSON file to a
Protobuf message (using `libjsonpbparse`), it also checks the following:
- Whether there are fields unknown to the schema. All fields in the JSON file
must be well defined in the schema.
- Whether the Protobuf file defines JSON keys clearly. The JSON keys must be
the `json_name` option of a Protobuf field, or name of a Protobuf field if
`json_name` is not defined. `lowerCamelCase` supported by `libprotobuf` is
explicitly disallowed (unless explicitly used in `json_name`). For example,
in the following Protobuf file, only keys `foo_bar` and `barBaz` are allowed
in the JSON file:
```
message Foo {
string foo_bar = 1;
string bar_baz = 2 [json_name = "barBaz"];
}
```
- Whether `json == convert_to_json(convert_to_pb(json))`, using `libprotobuf`.
This imposes additional restrictions including:
- Enum values must be present as names (not integer values) in the JSON file.
- 64-bit integers and special floating point values (infinity, NaN) must
always be strings.
## Defining a JSON schema using Protobuf
Check [JSON Mapping](https://developers.google.com/protocol-buffers/docs/proto3#json)
before defining a Protobuf object as a JSON schema. In general:
- **Use proto3**. `libjsonverify` does not support proto2.
- JSON booleans should be `bool`.
- JSON numbers should be `(s|fixed|u|)int32`, `float`, or `double` in the schema
- JSON strings are generally `string`s, but if you want to impose more
restrictions on the string, you can also use `Timestamp`, `bytes`,
**`float`** or **`double`** (if NaN and infinity are valid values),
enumerations, etc.
- If a custom enumeration is used, parser code should **NOT** error when the
enumeration value name is unknown, as enumeration definitions may be
extended in the future.
- JSON arrays should be repeated fields.
- JSON objects should be a well-defined `message`, unless you have a good reason
to use `map<string, T>`.
- Don't use `Any`; it defeats the purpose of having the schema.
## Validating a JSON file against a Protobuf definition
Example:
```c++
#include <jsonpb/verify.h>
using namespace ::android::jsonpb;
std::unique_ptr<JsonSchemaTestConfig> CreateCgroupsParam() {
}
INSTANTIATE_TEST_SUITE_P(LibProcessgroupProto, JsonSchemaTest,
::testing::Values(MakeTestParam<Cgroups>("cgroups.json")));
```