Commit a8e800bd authored by cryptocode's avatar cryptocode Committed by Wouter van Oortmerssen

Add --force-empty-vectors option (#5653)

The rationale for this option is that JSON clients typically want empty arrays (i.e [] in the JSON) instead of missing properties, but not empty strings when the value isn't set.
--force-empty is kept as-is, i.e. it will force both empty strings and vectors.

Closes #5652
parent d7530ae9
...@@ -203,5 +203,8 @@ Additional options: ...@@ -203,5 +203,8 @@ Additional options:
- `--force-empty` : When serializing from object API representation, force - `--force-empty` : When serializing from object API representation, force
strings and vectors to empty rather than null. strings and vectors to empty rather than null.
- `--force-empty-vectors` : When serializing from object API representation, force
vectors to empty rather than null.
NOTE: short-form options for generators are deprecated, use the long form NOTE: short-form options for generators are deprecated, use the long form
whenever possible. whenever possible.
...@@ -588,9 +588,13 @@ struct IDLOptions { ...@@ -588,9 +588,13 @@ struct IDLOptions {
// for code generation. // for code generation.
unsigned long lang_to_generate; unsigned long lang_to_generate;
// If set (default behavior), empty string and vector fields will be set to // If set (default behavior), empty string fields will be set to nullptr to make
// nullptr to make the flatbuffer more compact. // the flatbuffer more compact.
bool set_empty_to_null; bool set_empty_strings_to_null;
// If set (default behavior), empty vector fields will be set to nullptr to make
// the flatbuffer more compact.
bool set_empty_vectors_to_null;
IDLOptions() IDLOptions()
: use_flexbuffers(false), : use_flexbuffers(false),
...@@ -635,7 +639,8 @@ struct IDLOptions { ...@@ -635,7 +639,8 @@ struct IDLOptions {
lang(IDLOptions::kJava), lang(IDLOptions::kJava),
mini_reflect(IDLOptions::kNone), mini_reflect(IDLOptions::kNone),
lang_to_generate(0), lang_to_generate(0),
set_empty_to_null(true) {} set_empty_strings_to_null(true),
set_empty_vectors_to_null(true) {}
}; };
// This encapsulates where the parser is in the current source file. // This encapsulates where the parser is in the current source file.
......
...@@ -63,7 +63,7 @@ std::string FlatCompiler::GetUsageString(const char *program_name) const { ...@@ -63,7 +63,7 @@ std::string FlatCompiler::GetUsageString(const char *program_name) const {
const Generator &g = params_.generators[i]; const Generator &g = params_.generators[i];
std::stringstream full_name; std::stringstream full_name;
full_name << std::setw(12) << std::left << g.generator_opt_long; full_name << std::setw(16) << std::left << g.generator_opt_long;
const char *name = g.generator_opt_short ? g.generator_opt_short : " "; const char *name = g.generator_opt_short ? g.generator_opt_short : " ";
const char *help = g.generator_help; const char *help = g.generator_help;
...@@ -71,86 +71,88 @@ std::string FlatCompiler::GetUsageString(const char *program_name) const { ...@@ -71,86 +71,88 @@ std::string FlatCompiler::GetUsageString(const char *program_name) const {
} }
// clang-format off // clang-format off
ss << ss <<
" -o PATH Prefix PATH to all generated files.\n" " -o PATH Prefix PATH to all generated files.\n"
" -I PATH Search for includes in the specified path.\n" " -I PATH Search for includes in the specified path.\n"
" -M Print make rules for generated files.\n" " -M Print make rules for generated files.\n"
" --version Print the version number of flatc and exit.\n" " --version Print the version number of flatc and exit.\n"
" --strict-json Strict JSON: field names must be / will be quoted,\n" " --strict-json Strict JSON: field names must be / will be quoted,\n"
" no trailing commas in tables/vectors.\n" " no trailing commas in tables/vectors.\n"
" --allow-non-utf8 Pass non-UTF-8 input through parser and emit nonstandard\n" " --allow-non-utf8 Pass non-UTF-8 input through parser and emit nonstandard\n"
" \\x escapes in JSON. (Default is to raise parse error on\n" " \\x escapes in JSON. (Default is to raise parse error on\n"
" non-UTF-8 input.)\n" " non-UTF-8 input.)\n"
" --natural-utf8 Output strings with UTF-8 as human-readable strings.\n" " --natural-utf8 Output strings with UTF-8 as human-readable strings.\n"
" By default, UTF-8 characters are printed as \\uXXXX escapes.\n" " By default, UTF-8 characters are printed as \\uXXXX escapes.\n"
" --defaults-json Output fields whose value is the default when\n" " --defaults-json Output fields whose value is the default when\n"
" writing JSON\n" " writing JSON\n"
" --unknown-json Allow fields in JSON that are not defined in the\n" " --unknown-json Allow fields in JSON that are not defined in the\n"
" schema. These fields will be discared when generating\n" " schema. These fields will be discared when generating\n"
" binaries.\n" " binaries.\n"
" --no-prefix Don\'t prefix enum values with the enum type in C++.\n" " --no-prefix Don\'t prefix enum values with the enum type in C++.\n"
" --scoped-enums Use C++11 style scoped and strongly typed enums.\n" " --scoped-enums Use C++11 style scoped and strongly typed enums.\n"
" also implies --no-prefix.\n" " also implies --no-prefix.\n"
" --gen-includes (deprecated), this is the default behavior.\n" " --gen-includes (deprecated), this is the default behavior.\n"
" If the original behavior is required (no include\n" " If the original behavior is required (no include\n"
" statements) use --no-includes.\n" " statements) use --no-includes.\n"
" --no-includes Don\'t generate include statements for included\n" " --no-includes Don\'t generate include statements for included\n"
" schemas the generated file depends on (C++ / Python).\n" " schemas the generated file depends on (C++ / Python).\n"
" --gen-mutable Generate accessors that can mutate buffers in-place.\n" " --gen-mutable Generate accessors that can mutate buffers in-place.\n"
" --gen-onefile Generate single output file for C# and Go.\n" " --gen-onefile Generate single output file for C# and Go.\n"
" --gen-name-strings Generate type name functions for C++.\n" " --gen-name-strings Generate type name functions for C++.\n"
" --gen-object-api Generate an additional object-based API.\n" " --gen-object-api Generate an additional object-based API.\n"
" --gen-compare Generate operator== for object-based API types.\n" " --gen-compare Generate operator== for object-based API types.\n"
" --gen-nullable Add Clang _Nullable for C++ pointer. or @Nullable for Java\n" " --gen-nullable Add Clang _Nullable for C++ pointer. or @Nullable for Java\n"
" --java-checkerframework Add @Pure for Java.\n" " --java-checkerframe work Add @Pure for Java.\n"
" --gen-generated Add @Generated annotation for Java\n" " --gen-generated Add @Generated annotation for Java\n"
" --gen-all Generate not just code for the current schema files,\n" " --gen-all Generate not just code for the current schema files,\n"
" but for all files it includes as well.\n" " but for all files it includes as well.\n"
" If the language uses a single file for output (by default\n" " If the language uses a single file for output (by default\n"
" the case for C++ and JS), all code will end up in this one\n" " the case for C++ and JS), all code will end up in this one\n"
" file.\n" " file.\n"
" --cpp-include Adds an #include in generated file.\n" " --cpp-include Adds an #include in generated file.\n"
" --cpp-ptr-type T Set object API pointer type (default std::unique_ptr).\n" " --cpp-ptr-type T Set object API pointer type (default std::unique_ptr).\n"
" --cpp-str-type T Set object API string type (default std::string).\n" " --cpp-str-type T Set object API string type (default std::string).\n"
" T::c_str(), T::length() and T::empty() must be supported.\n" " T::c_str(), T::length() and T::empty() must be supported.\n"
" The custom type also needs to be constructible from std::string\n" " The custom type also needs to be constructible from std::string\n"
" (see the --cpp-str-flex-ctor option to change this behavior).\n" " (see the --cpp-str-flex-ctor option to change this behavior).\n"
" --cpp-str-flex-ctor Don't construct custom string types by passing std::string\n" " --cpp-str-flex-ctor Don't construct custom string types by passing std::string\n"
" from Flatbuffers, but (char* + length).\n" " from Flatbuffers, but (char* + length).\n"
" --object-prefix Customise class prefix for C++ object-based API.\n" " --object-prefix Customise class prefix for C++ object-based API.\n"
" --object-suffix Customise class suffix for C++ object-based API.\n" " --object-suffix Customise class suffix for C++ object-based API.\n"
" Default value is \"T\".\n" " Default value is \"T\".\n"
" --no-js-exports Removes Node.js style export lines in JS.\n" " --no-js-exports Removes Node.js style export lines in JS.\n"
" --goog-js-export Uses goog.exports* for closure compiler exporting in JS.\n" " --goog-js-export Uses goog.exports* for closure compiler exporting in JS.\n"
" --es6-js-export Uses ECMAScript 6 export style lines in JS.\n" " --es6-js-export Uses ECMAScript 6 export style lines in JS.\n"
" --go-namespace Generate the overrided namespace in Golang.\n" " --go-namespace Generate the overrided namespace in Golang.\n"
" --go-import Generate the overrided import for flatbuffers in Golang\n" " --go-import Generate the overrided import for flatbuffers in Golang\n"
" (default is \"github.com/google/flatbuffers/go\").\n" " (default is \"github.com/google/flatbuffers/go\").\n"
" --raw-binary Allow binaries without file_indentifier to be read.\n" " --raw-binary Allow binaries without file_indentifier to be read.\n"
" This may crash flatc given a mismatched schema.\n" " This may crash flatc given a mismatched schema.\n"
" --size-prefixed Input binaries are size prefixed buffers.\n" " --size-prefixed Input binaries are size prefixed buffers.\n"
" --proto Input is a .proto, translate to .fbs.\n" " --proto Input is a .proto, translate to .fbs.\n"
" --oneof-union Translate .proto oneofs to flatbuffer unions.\n" " --oneof-union Translate .proto oneofs to flatbuffer unions.\n"
" --grpc Generate GRPC interfaces for the specified languages.\n" " --grpc Generate GRPC interfaces for the specified languages.\n"
" --schema Serialize schemas instead of JSON (use with -b).\n" " --schema Serialize schemas instead of JSON (use with -b).\n"
" --bfbs-comments Add doc comments to the binary schema files.\n" " --bfbs-comments Add doc comments to the binary schema files.\n"
" --bfbs-builtins Add builtin attributes to the binary schema files.\n" " --bfbs-builtins Add builtin attributes to the binary schema files.\n"
" --conform FILE Specify a schema the following schemas should be\n" " --conform FILE Specify a schema the following schemas should be\n"
" an evolution of. Gives errors if not.\n" " an evolution of. Gives errors if not.\n"
" --conform-includes Include path for the schema given with --conform PATH\n" " --conform-includes Include path for the schema given with --conform PATH\n"
" --include-prefix Prefix this path to any generated include statements.\n" " --include-prefix Prefix this path to any generated include statements.\n"
" PATH\n" " PATH\n"
" --keep-prefix Keep original prefix of schema include statement.\n" " --keep-prefix Keep original prefix of schema include statement.\n"
" --no-fb-import Don't include flatbuffers import statement for TypeScript.\n" " --no-fb-import Don't include flatbuffers import statement for TypeScript.\n"
" --no-ts-reexport Don't re-export imported dependencies for TypeScript.\n" " --no-ts-reexport Don't re-export imported dependencies for TypeScript.\n"
" --short-names Use short function names for JS and TypeScript.\n" " --short-names Use short function names for JS and TypeScript.\n"
" --reflect-types Add minimal type reflection to code generation.\n" " --reflect-types Add minimal type reflection to code generation.\n"
" --reflect-names Add minimal type/name reflection.\n" " --reflect-names Add minimal type/name reflection.\n"
" --root-type T Select or override the default root_type\n" " --root-type T Select or override the default root_type\n"
" --force-defaults Emit default values in binary output from JSON\n" " --force-defaults Emit default values in binary output from JSON\n"
" --force-empty When serializing from object API representation,\n" " --force-empty When serializing from object API representation,\n"
" force strings and vectors to empty rather than null.\n" " force strings and vectors to empty rather than null.\n"
" --flexbuffers Used with \"binary\" and \"json\" options, it generates\n" " --force-empty-vectors When serializing from object API representation,\n"
" data using schema-less FlexBuffers.\n" " force vectors to empty rather than null.\n"
" --flexbuffers Used with \"binary\" and \"json\" options, it generates\n"
" data using schema-less FlexBuffers.\n"
"FILEs may be schemas (must end in .fbs), binary schemas (must end in .bfbs),\n" "FILEs may be schemas (must end in .fbs), binary schemas (must end in .bfbs),\n"
"or JSON files (conforming to preceding schema). FILEs after the -- must be\n" "or JSON files (conforming to preceding schema). FILEs after the -- must be\n"
"binary flatbuffer format files.\n" "binary flatbuffer format files.\n"
...@@ -323,7 +325,10 @@ int FlatCompiler::Compile(int argc, const char **argv) { ...@@ -323,7 +325,10 @@ int FlatCompiler::Compile(int argc, const char **argv) {
} else if (arg == "--force-defaults") { } else if (arg == "--force-defaults") {
opts.force_defaults = true; opts.force_defaults = true;
} else if (arg == "--force-empty") { } else if (arg == "--force-empty") {
opts.set_empty_to_null = false; opts.set_empty_strings_to_null = false;
opts.set_empty_vectors_to_null = false;
} else if (arg == "--force-empty-vectors") {
opts.set_empty_vectors_to_null = false;
} else if (arg == "--java-primitive-has-method") { } else if (arg == "--java-primitive-has-method") {
opts.java_primitive_has_method = true; opts.java_primitive_has_method = true;
} else if (arg == "--flexbuffers") { } else if (arg == "--flexbuffers") {
......
...@@ -2452,10 +2452,10 @@ class CppGenerator : public BaseGenerator { ...@@ -2452,10 +2452,10 @@ class CppGenerator : public BaseGenerator {
// For optional fields, check to see if there actually is any data // For optional fields, check to see if there actually is any data
// in _o->field before attempting to access it. If there isn't, // in _o->field before attempting to access it. If there isn't,
// depending on set_empty_to_null either set it to 0 or an empty string. // depending on set_empty_strings_to_null either set it to 0 or an empty string.
if (!field.required) { if (!field.required) {
auto empty_value = auto empty_value =
opts.set_empty_to_null ? "0" : "_fbb.CreateSharedString(\"\")"; opts.set_empty_strings_to_null ? "0" : "_fbb.CreateSharedString(\"\")";
code = value + ".empty() ? " + empty_value + " : " + code; code = value + ".empty() ? " + empty_value + " : " + code;
} }
break; break;
...@@ -2557,10 +2557,10 @@ class CppGenerator : public BaseGenerator { ...@@ -2557,10 +2557,10 @@ class CppGenerator : public BaseGenerator {
} }
} }
// If set_empty_to_null option is enabled, for optional fields, check to // If set_empty_vectors_to_null option is enabled, for optional fields, check to
// see if there actually is any data in _o->field before attempting to // see if there actually is any data in _o->field before attempting to
// access it. // access it.
if (opts.set_empty_to_null && !field.required) { if (opts.set_empty_vectors_to_null && !field.required) {
code = value + ".size() ? " + code + " : 0"; code = value + ".size() ? " + code + " : 0";
} }
break; break;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment