summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tests/json/test_json.cc41
-rw-r--r--upb/json/parser.c11
-rw-r--r--upb/json/parser.rl11
-rw-r--r--upb/json/printer.c30
-rw-r--r--upb/json/printer.h14
5 files changed, 79 insertions, 28 deletions
diff --git a/tests/json/test_json.cc b/tests/json/test_json.cc
index 5ca04fc..6874131 100644
--- a/tests/json/test_json.cc
+++ b/tests/json/test_json.cc
@@ -36,6 +36,17 @@ static TestCase kTestRoundtripMessages[] = {
"{\"foo\":2}]}"),
EXPECT_SAME
},
+ // We must also recognize raw proto names.
+ {
+ TEST("{\"optional_int32\":-42,\"optional_string\":\"Test\\u0001Message\","
+ "\"optional_msg\":{\"foo\":42},"
+ "\"optional_bool\":true,\"repeated_msg\":[{\"foo\":1},"
+ "{\"foo\":2}]}"),
+ EXPECT("{\"optionalInt32\":-42,\"optionalString\":\"Test\\u0001Message\","
+ "\"optionalMsg\":{\"foo\":42},"
+ "\"optionalBool\":true,\"repeatedMsg\":[{\"foo\":1},"
+ "{\"foo\":2}]}")
+ },
// Test special escapes in strings.
{
TEST("{\"repeatedString\":[\"\\b\",\"\\r\",\"\\n\",\"\\f\",\"\\t\","
@@ -112,6 +123,18 @@ static TestCase kTestRoundtripMessages[] = {
TEST_SENTINEL
};
+static TestCase kTestRoundtripMessagesPreserve[] = {
+ // Test most fields here.
+ {
+ TEST("{\"optional_int32\":-42,\"optional_string\":\"Test\\u0001Message\","
+ "\"optional_msg\":{\"foo\":42},"
+ "\"optional_bool\":true,\"repeated_msg\":[{\"foo\":1},"
+ "{\"foo\":2}]}"),
+ EXPECT_SAME
+ },
+ TEST_SENTINEL
+};
+
static void AddField(upb::MessageDef* message,
int number,
const char* name,
@@ -323,7 +346,7 @@ void test_json_roundtrip() {
upb::reffed_ptr<upb::SymbolTable> symtab(upb::SymbolTable::New());
const upb::MessageDef* md = BuildTestMessage(symtab.get());
upb::reffed_ptr<const upb::Handlers> serialize_handlers(
- upb::json::Printer::NewHandlers(md));
+ upb::json::Printer::NewHandlers(md, false));
upb::reffed_ptr<const upb::json::ParserMethod> parser_method(
upb::json::ParserMethod::New(md));
@@ -340,6 +363,22 @@ void test_json_roundtrip() {
i);
}
}
+
+ serialize_handlers = upb::json::Printer::NewHandlers(md, true);
+
+ for (const TestCase* test_case = kTestRoundtripMessagesPreserve;
+ test_case->input != NULL; test_case++) {
+ const char *expected =
+ (test_case->expected == EXPECT_SAME) ?
+ test_case->input :
+ test_case->expected;
+
+ for (size_t i = 0; i < strlen(test_case->input); i++) {
+ test_json_roundtrip_message(test_case->input, expected,
+ serialize_handlers.get(), parser_method.get(),
+ i);
+ }
+ }
}
extern "C" {
diff --git a/upb/json/parser.c b/upb/json/parser.c
index e1a334d..1662f1a 100644
--- a/upb/json/parser.c
+++ b/upb/json/parser.c
@@ -1527,7 +1527,7 @@ _again:
#line 1270 "upb/json/parser.rl"
if (p != pe) {
- upb_status_seterrf(&parser->status, "Parse error at %s\n", p);
+ upb_status_seterrf(&parser->status, "Parse error at '%.*s'\n", p, pe - p);
upb_env_reporterror(parser->env, &parser->status);
} else {
capture_suspend(parser, &p);
@@ -1628,6 +1628,7 @@ static void add_jsonname_table(upb_json_parsermethod *m, const upb_msgdef* md) {
upb_msg_field_next(&i)) {
const upb_fielddef *f = upb_msg_iter_field(&i);
+ /* Add an entry for the JSON name. */
size_t field_len = upb_fielddef_getjsonname(f, buf, len);
if (field_len > len) {
size_t len2;
@@ -1638,10 +1639,10 @@ static void add_jsonname_table(upb_json_parsermethod *m, const upb_msgdef* md) {
}
upb_strtable_insert(t, buf, upb_value_constptr(f));
- if (getenv("UPB_JSON_ACCEPT_LEGACY_FIELD_NAMES")) {
- /* Temporary code to help people migrate if they were depending on the
- * old, non-proto3-json-compliant field names. In this case we
- * recognize both old names and new names. */
+ if (strcmp(buf, upb_fielddef_name(f)) != 0) {
+ /* Since the JSON name is different from the regular field name, add an
+ * entry for the raw name (compliant proto3 JSON parsers must accept
+ * both). */
upb_strtable_insert(t, upb_fielddef_name(f), upb_value_constptr(f));
}
diff --git a/upb/json/parser.rl b/upb/json/parser.rl
index eecb3b2..943a490 100644
--- a/upb/json/parser.rl
+++ b/upb/json/parser.rl
@@ -1269,7 +1269,7 @@ size_t parse(void *closure, const void *hd, const char *buf, size_t size,
%% write exec;
if (p != pe) {
- upb_status_seterrf(&parser->status, "Parse error at %s\n", p);
+ upb_status_seterrf(&parser->status, "Parse error at '%.*s'\n", p, pe - p);
upb_env_reporterror(parser->env, &parser->status);
} else {
capture_suspend(parser, &p);
@@ -1363,6 +1363,7 @@ static void add_jsonname_table(upb_json_parsermethod *m, const upb_msgdef* md) {
upb_msg_field_next(&i)) {
const upb_fielddef *f = upb_msg_iter_field(&i);
+ /* Add an entry for the JSON name. */
size_t field_len = upb_fielddef_getjsonname(f, buf, len);
if (field_len > len) {
size_t len2;
@@ -1373,10 +1374,10 @@ static void add_jsonname_table(upb_json_parsermethod *m, const upb_msgdef* md) {
}
upb_strtable_insert(t, buf, upb_value_constptr(f));
- if (getenv("UPB_JSON_ACCEPT_LEGACY_FIELD_NAMES")) {
- /* Temporary code to help people migrate if they were depending on the
- * old, non-proto3-json-compliant field names. In this case we
- * recognize both old names and new names. */
+ if (strcmp(buf, upb_fielddef_name(f)) != 0) {
+ /* Since the JSON name is different from the regular field name, add an
+ * entry for the raw name (compliant proto3 JSON parsers must accept
+ * both). */
upb_strtable_insert(t, upb_fielddef_name(f), upb_value_constptr(f));
}
diff --git a/upb/json/printer.c b/upb/json/printer.c
index e6135bb..230aa0d 100644
--- a/upb/json/printer.c
+++ b/upb/json/printer.c
@@ -44,12 +44,11 @@ void freestrpc(void *ptr) {
}
/* Convert fielddef name to JSON name and return as a string piece. */
-strpc *newstrpc(upb_handlers *h, const upb_fielddef *f) {
+strpc *newstrpc(upb_handlers *h, const upb_fielddef *f,
+ bool preserve_fieldnames) {
/* TODO(haberman): handle malloc failure. */
strpc *ret = malloc(sizeof(*ret));
- if (getenv("UPB_JSON_WRITE_LEGACY_FIELD_NAMES")) {
- /* Temporary code to help people migrate if they were depending on the
- * old, non-proto3-json-compliant field names. */
+ if (preserve_fieldnames) {
ret->ptr = upb_strdup(upb_fielddef_name(f));
ret->len = strlen(ret->ptr);
} else {
@@ -565,10 +564,11 @@ static size_t mapkey_bytes(void *closure, const void *handler_data,
static void set_enum_hd(upb_handlers *h,
const upb_fielddef *f,
+ bool preserve_fieldnames,
upb_handlerattr *attr) {
EnumHandlerData *hd = malloc(sizeof(EnumHandlerData));
hd->enumdef = (const upb_enumdef *)upb_fielddef_subdef(f);
- hd->keyname = newstrpc(h, f);
+ hd->keyname = newstrpc(h, f, preserve_fieldnames);
upb_handlers_addcleanup(h, hd, free);
upb_handlerattr_sethandlerdata(attr, hd);
}
@@ -585,7 +585,8 @@ static void set_enum_hd(upb_handlers *h,
* our sources that emit mapentry messages do so canonically (with one key
* field, and then one value field), so this is not a pressing concern at the
* moment. */
-void printer_sethandlers_mapentry(const void *closure, upb_handlers *h) {
+void printer_sethandlers_mapentry(const void *closure, bool preserve_fieldnames,
+ upb_handlers *h) {
const upb_msgdef *md = upb_handlers_msgdef(h);
/* A mapentry message is printed simply as '"key": value'. Rather than
@@ -659,7 +660,7 @@ void printer_sethandlers_mapentry(const void *closure, upb_handlers *h) {
break;
case UPB_TYPE_ENUM: {
upb_handlerattr enum_attr = UPB_HANDLERATTR_INITIALIZER;
- set_enum_hd(h, value_field, &enum_attr);
+ set_enum_hd(h, value_field, preserve_fieldnames, &enum_attr);
upb_handlers_setint32(h, value_field, mapvalue_enum, &enum_attr);
upb_handlerattr_uninit(&enum_attr);
break;
@@ -678,13 +679,13 @@ void printer_sethandlers(const void *closure, upb_handlers *h) {
bool is_mapentry = upb_msgdef_mapentry(md);
upb_handlerattr empty_attr = UPB_HANDLERATTR_INITIALIZER;
upb_msg_field_iter i;
-
- UPB_UNUSED(closure);
+ const bool *preserve_fieldnames_ptr = closure;
+ const bool preserve_fieldnames = *preserve_fieldnames_ptr;
if (is_mapentry) {
/* mapentry messages are sufficiently different that we handle them
* separately. */
- printer_sethandlers_mapentry(closure, h);
+ printer_sethandlers_mapentry(closure, preserve_fieldnames, h);
return;
}
@@ -705,7 +706,8 @@ void printer_sethandlers(const void *closure, upb_handlers *h) {
const upb_fielddef *f = upb_msg_iter_field(&i);
upb_handlerattr name_attr = UPB_HANDLERATTR_INITIALIZER;
- upb_handlerattr_sethandlerdata(&name_attr, newstrpc(h, f));
+ upb_handlerattr_sethandlerdata(&name_attr,
+ newstrpc(h, f, preserve_fieldnames));
if (upb_fielddef_ismap(f)) {
upb_handlers_setstartseq(h, f, startmap, &name_attr);
@@ -728,7 +730,7 @@ void printer_sethandlers(const void *closure, upb_handlers *h) {
* option later to control this behavior, but we will wait for a real
* need first. */
upb_handlerattr enum_attr = UPB_HANDLERATTR_INITIALIZER;
- set_enum_hd(h, f, &enum_attr);
+ set_enum_hd(h, f, preserve_fieldnames, &enum_attr);
if (upb_fielddef_isseq(f)) {
upb_handlers_setint32(h, f, repeated_enum, &enum_attr);
@@ -805,6 +807,8 @@ upb_sink *upb_json_printer_input(upb_json_printer *p) {
}
const upb_handlers *upb_json_printer_newhandlers(const upb_msgdef *md,
+ bool preserve_fieldnames,
const void *owner) {
- return upb_handlers_newfrozen(md, owner, printer_sethandlers, NULL);
+ return upb_handlers_newfrozen(
+ md, owner, printer_sethandlers, &preserve_fieldnames);
}
diff --git a/upb/json/printer.h b/upb/json/printer.h
index 84d814c..36a24e9 100644
--- a/upb/json/printer.h
+++ b/upb/json/printer.h
@@ -36,8 +36,12 @@ class upb::json::Printer {
/* The input to the printer. */
Sink* input();
- /* Returns handlers for printing according to the specified schema. */
- static reffed_ptr<const Handlers> NewHandlers(const upb::MessageDef* md);
+ /* Returns handlers for printing according to the specified schema.
+ * If preserve_proto_fieldnames is true, the output JSON will use the
+ * original .proto field names (ie. {"my_field":3}) instead of using
+ * camelCased names, which is the default: (eg. {"myField":3}). */
+ static reffed_ptr<const Handlers> NewHandlers(const upb::MessageDef* md,
+ bool preserve_proto_fieldnames);
static const size_t kSize = UPB_JSON_PRINTER_SIZE;
@@ -54,6 +58,7 @@ upb_json_printer *upb_json_printer_create(upb_env *e, const upb_handlers *h,
upb_bytessink *output);
upb_sink *upb_json_printer_input(upb_json_printer *p);
const upb_handlers *upb_json_printer_newhandlers(const upb_msgdef *md,
+ bool preserve_fieldnames,
const void *owner);
UPB_END_EXTERN_C
@@ -68,8 +73,9 @@ inline Printer* Printer::Create(Environment* env, const upb::Handlers* handlers,
}
inline Sink* Printer::input() { return upb_json_printer_input(this); }
inline reffed_ptr<const Handlers> Printer::NewHandlers(
- const upb::MessageDef *md) {
- const Handlers* h = upb_json_printer_newhandlers(md, &h);
+ const upb::MessageDef *md, bool preserve_proto_fieldnames) {
+ const Handlers* h = upb_json_printer_newhandlers(
+ md, preserve_proto_fieldnames, &h);
return reffed_ptr<const Handlers>(h, &h);
}
} /* namespace json */
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback