Fix Empty ListValue/Struct json encoding (#5532)
* Fix Empty ListValue/Struct json encoding * Add test for empty ListValue
This commit is contained in:
parent
aa5c12e882
commit
11c979b591
@ -1099,6 +1099,12 @@ static void putrawmsg(MessageHeader* msg, const Descriptor* desc,
|
||||
bool open_msg TSRMLS_DC);
|
||||
static void putjsonany(MessageHeader* msg, const Descriptor* desc,
|
||||
upb_sink* sink, int depth TSRMLS_DC);
|
||||
static void putjsonlistvalue(
|
||||
MessageHeader* msg, const Descriptor* desc,
|
||||
upb_sink* sink, int depth TSRMLS_DC);
|
||||
static void putjsonstruct(
|
||||
MessageHeader* msg, const Descriptor* desc,
|
||||
upb_sink* sink, int depth TSRMLS_DC);
|
||||
|
||||
static void putstr(zval* str, const upb_fielddef* f, upb_sink* sink,
|
||||
bool force_default);
|
||||
@ -1342,17 +1348,88 @@ static void putjsonany(MessageHeader* msg, const Descriptor* desc,
|
||||
upb_sink_endmsg(sink, &status);
|
||||
}
|
||||
|
||||
static void putjsonlistvalue(
|
||||
MessageHeader* msg, const Descriptor* desc,
|
||||
upb_sink* sink, int depth TSRMLS_DC) {
|
||||
upb_status status;
|
||||
upb_sink subsink;
|
||||
const upb_fielddef* f = upb_msgdef_itof(desc->msgdef, 1);
|
||||
uint32_t offset = desc->layout->fields[upb_fielddef_index(f)].offset;
|
||||
zval* array;
|
||||
RepeatedField* intern;
|
||||
HashTable *ht;
|
||||
int size, i;
|
||||
|
||||
upb_sink_startmsg(sink);
|
||||
|
||||
array = CACHED_PTR_TO_ZVAL_PTR(
|
||||
DEREF(message_data(msg), offset, CACHED_VALUE*));
|
||||
intern = UNBOX(RepeatedField, array);
|
||||
ht = PHP_PROTO_HASH_OF(intern->array);
|
||||
size = zend_hash_num_elements(ht);
|
||||
|
||||
if (size == 0) {
|
||||
upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink);
|
||||
upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ));
|
||||
} else {
|
||||
putarray(array, f, sink, depth, true TSRMLS_CC);
|
||||
}
|
||||
|
||||
upb_sink_endmsg(sink, &status);
|
||||
}
|
||||
|
||||
static void putjsonstruct(
|
||||
MessageHeader* msg, const Descriptor* desc,
|
||||
upb_sink* sink, int depth TSRMLS_DC) {
|
||||
upb_status status;
|
||||
upb_sink subsink;
|
||||
const upb_fielddef* f = upb_msgdef_itof(desc->msgdef, 1);
|
||||
uint32_t offset = desc->layout->fields[upb_fielddef_index(f)].offset;
|
||||
zval* map;
|
||||
Map* intern;
|
||||
int size;
|
||||
|
||||
upb_sink_startmsg(sink);
|
||||
|
||||
map = CACHED_PTR_TO_ZVAL_PTR(
|
||||
DEREF(message_data(msg), offset, CACHED_VALUE*));
|
||||
intern = UNBOX(Map, map);
|
||||
size = upb_strtable_count(&intern->table);
|
||||
|
||||
if (size == 0) {
|
||||
upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink);
|
||||
upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ));
|
||||
} else {
|
||||
putmap(map, f, sink, depth, true TSRMLS_CC);
|
||||
}
|
||||
|
||||
upb_sink_endmsg(sink, &status);
|
||||
}
|
||||
|
||||
static void putrawmsg(MessageHeader* msg, const Descriptor* desc,
|
||||
upb_sink* sink, int depth, bool is_json,
|
||||
bool open_msg TSRMLS_DC) {
|
||||
upb_msg_field_iter i;
|
||||
upb_status status;
|
||||
|
||||
if (is_json && upb_msgdef_wellknowntype(desc->msgdef) == UPB_WELLKNOWN_ANY) {
|
||||
if (is_json &&
|
||||
upb_msgdef_wellknowntype(desc->msgdef) == UPB_WELLKNOWN_ANY) {
|
||||
putjsonany(msg, desc, sink, depth TSRMLS_CC);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_json &&
|
||||
upb_msgdef_wellknowntype(desc->msgdef) == UPB_WELLKNOWN_LISTVALUE) {
|
||||
putjsonlistvalue(msg, desc, sink, depth TSRMLS_CC);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_json &&
|
||||
upb_msgdef_wellknowntype(desc->msgdef) == UPB_WELLKNOWN_STRUCT) {
|
||||
putjsonstruct(msg, desc, sink, depth TSRMLS_CC);
|
||||
return;
|
||||
}
|
||||
|
||||
if (open_msg) {
|
||||
upb_sink_startmsg(sink);
|
||||
}
|
||||
|
@ -1383,6 +1383,24 @@ class Message
|
||||
$timestamp = GPBUtil::formatTimestamp($this);
|
||||
$timestamp = json_encode($timestamp);
|
||||
$output->writeRaw($timestamp, strlen($timestamp));
|
||||
} elseif (get_class($this) === 'Google\Protobuf\ListValue') {
|
||||
$field = $this->desc->getField()[1];
|
||||
if (!$this->existField($field)) {
|
||||
$output->writeRaw("[]", 2);
|
||||
} else {
|
||||
if (!$this->serializeFieldToJsonStream($output, $field)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} elseif (get_class($this) === 'Google\Protobuf\Struct') {
|
||||
$field = $this->desc->getField()[1];
|
||||
if (!$this->existField($field)) {
|
||||
$output->writeRaw("{}", 2);
|
||||
} else {
|
||||
if (!$this->serializeFieldToJsonStream($output, $field)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!GPBUtil::hasSpecialJsonMapping($this)) {
|
||||
$output->writeRaw("{", 1);
|
||||
@ -1844,6 +1862,24 @@ class Message
|
||||
$timestamp = GPBUtil::formatTimestamp($this);
|
||||
$timestamp = json_encode($timestamp);
|
||||
$size += strlen($timestamp);
|
||||
} elseif (get_class($this) === 'Google\Protobuf\ListValue') {
|
||||
$field = $this->desc->getField()[1];
|
||||
if ($this->existField($field)) {
|
||||
$field_size = $this->fieldJsonByteSize($field);
|
||||
$size += $field_size;
|
||||
} else {
|
||||
// Size for "[]".
|
||||
$size += 2;
|
||||
}
|
||||
} elseif (get_class($this) === 'Google\Protobuf\Struct') {
|
||||
$field = $this->desc->getField()[1];
|
||||
if ($this->existField($field)) {
|
||||
$field_size = $this->fieldJsonByteSize($field);
|
||||
$size += $field_size;
|
||||
} else {
|
||||
// Size for "{}".
|
||||
$size += 2;
|
||||
}
|
||||
} else {
|
||||
if (!GPBUtil::hasSpecialJsonMapping($this)) {
|
||||
// Size for "{}".
|
||||
|
@ -898,6 +898,13 @@ class EncodeDecodeTest extends TestBase
|
||||
$this->assertSame("[1.5]", $m->serializeToJsonString());
|
||||
}
|
||||
|
||||
public function testEncodeEmptyListValue()
|
||||
{
|
||||
$m = new Struct();
|
||||
$m->setFields(['test' => (new Value())->setListValue(new ListValue())]);
|
||||
$this->assertSame('{"test":[]}', $m->serializeToJsonString());
|
||||
}
|
||||
|
||||
public function testDecodeTopLevelStruct()
|
||||
{
|
||||
$m = new Struct();
|
||||
@ -917,6 +924,13 @@ class EncodeDecodeTest extends TestBase
|
||||
$this->assertSame("{\"a\":1.5}", $m->serializeToJsonString());
|
||||
}
|
||||
|
||||
public function testEncodeEmptyStruct()
|
||||
{
|
||||
$m = new Struct();
|
||||
$m->setFields(['test' => (new Value())->setStructValue(new Struct())]);
|
||||
$this->assertSame('{"test":{}}', $m->serializeToJsonString());
|
||||
}
|
||||
|
||||
public function testDecodeTopLevelAny()
|
||||
{
|
||||
// Make sure packed message has been created at least once.
|
||||
|
Loading…
Reference in New Issue
Block a user