Skip to content

Commit 0f8e4fd

Browse files
committed
Fix JSON reader in case of empty bytes field
1 parent a7a9352 commit 0f8e4fd

File tree

6 files changed

+138
-12
lines changed

6 files changed

+138
-12
lines changed

compiler/extensions/cpp/runtime/src/zserio/JsonReader.h

+10-4
Original file line numberDiff line numberDiff line change
@@ -381,18 +381,27 @@ template <typename ALLOC>
381381
void BytesAdapter<ALLOC>::beginArray()
382382
{
383383
if (m_state == BEGIN_ARRAY_BUFFER)
384+
{
384385
m_state = VISIT_VALUE_BUFFER;
386+
m_buffer = vector<uint8_t, ALLOC>(get_allocator());
387+
}
385388
else
389+
{
386390
throw CppRuntimeException("JsonReader: Unexpected beginArray in bytes!");
391+
}
387392
}
388393

389394
template <typename ALLOC>
390395
void BytesAdapter<ALLOC>::endArray()
391396
{
392397
if (m_state == VISIT_VALUE_BUFFER)
398+
{
393399
m_state = VISIT_KEY;
400+
}
394401
else
402+
{
395403
throw CppRuntimeException("JsonReader: Unexpected endArray in bytes!");
404+
}
396405
}
397406

398407
template <typename ALLOC>
@@ -440,10 +449,7 @@ void BytesAdapter<ALLOC>::visitValue(uint64_t uintValue)
440449
<< uintValue << "'!";
441450
}
442451

443-
if (!m_buffer.hasValue())
444-
m_buffer = vector<uint8_t, ALLOC>(1, static_cast<uint8_t>(uintValue), get_allocator());
445-
else
446-
m_buffer->push_back(static_cast<uint8_t>(uintValue));
452+
m_buffer->push_back(static_cast<uint8_t>(uintValue));
447453
}
448454
else
449455
{

compiler/extensions/cpp/runtime/test/zserio/JsonReaderTest.cpp

+40
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,46 @@ TEST(JsonReaderTest, readEmptyBitBuffer)
488488
reflectable->find("nested.creatorBitmask")->getUInt8());
489489
}
490490

491+
TEST(JsonReaderTest, readEmptyBytes)
492+
{
493+
std::stringstream str(
494+
"{\n"
495+
" \"value\": 13,\n"
496+
" \"nested\": {\n"
497+
" \"value\": 10,\n"
498+
" \"text\": \"nested\",\n"
499+
" \"externData\": {\n"
500+
" \"bitSize\": 0,\n"
501+
" \"buffer\": [\n"
502+
" ]\n"
503+
" },\n"
504+
" \"bytesData\": {\n"
505+
" \"buffer\": [\n"
506+
" ]\n"
507+
" },\n"
508+
" \"creatorEnum\": -1,\n"
509+
" \"creatorBitmask\": 1\n"
510+
" }\n"
511+
"}");
512+
513+
JsonReader jsonReader(str);
514+
auto reflectable = jsonReader.read(CreatorObject::typeInfo());
515+
ASSERT_TRUE(reflectable);
516+
517+
reflectable->initializeChildren();
518+
519+
ASSERT_EQ(13, reflectable->getField("value")->getUInt32());
520+
ASSERT_EQ(13, reflectable->getField("nested")->getParameter("param")->getUInt32());
521+
ASSERT_EQ(10, reflectable->find("nested.value")->getUInt32());
522+
ASSERT_EQ("nested"_sv, reflectable->find("nested.text")->getStringView());
523+
ASSERT_EQ(BitBuffer(), reflectable->find("nested.externData")->getBitBuffer());
524+
const Span<const uint8_t> bytesData = reflectable->find("nested.bytesData")->getBytes();
525+
ASSERT_EQ(0, bytesData.size());
526+
ASSERT_EQ(enumToValue(CreatorEnum::MinusOne), reflectable->find("nested.creatorEnum")->getInt8());
527+
ASSERT_EQ(CreatorBitmask(CreatorBitmask::Values::READ).getValue(),
528+
reflectable->find("nested.creatorBitmask")->getUInt8());
529+
}
530+
491531
TEST(JsonReaderTest, readStringifiedEnum)
492532
{
493533
checkReadStringifiedEnum("ONE", CreatorEnum::ONE);

compiler/extensions/java/runtime/src/zserio/runtime/json/JsonReader.java

+9-3
Original file line numberDiff line numberDiff line change
@@ -266,18 +266,27 @@ public void endObject()
266266
public void beginArray()
267267
{
268268
if (state == State.BEGIN_ARRAY_BUFFER)
269+
{
269270
state = State.VISIT_VALUE_BUFFER;
271+
buffer = new ArrayList<Byte>();
272+
}
270273
else
274+
{
271275
throw new ZserioError("JsonReader: Unexpected begin array in bytes!");
276+
}
272277
}
273278

274279
@Override
275280
public void endArray()
276281
{
277282
if (state == State.VISIT_VALUE_BUFFER)
283+
{
278284
state = State.VISIT_KEY;
285+
}
279286
else
287+
{
280288
throw new ZserioError("JsonReader: Unexpected end array in bytes!");
289+
}
281290
}
282291

283292
@Override
@@ -301,9 +310,6 @@ public void visitValue(Object value)
301310
{
302311
if (state == State.VISIT_VALUE_BUFFER && value instanceof BigInteger)
303312
{
304-
if (buffer == null)
305-
buffer = new ArrayList<Byte>();
306-
307313
// bit buffer stores 8-bit unsigned values in byte type
308314
final BigInteger intValue = (BigInteger)value;
309315
if (intValue.compareTo(BigInteger.ZERO) < 0 || intValue.compareTo(BigInteger.valueOf(255)) > 0)

compiler/extensions/java/runtime/test/zserio/runtime/json/JsonReaderTest.java

+39
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,45 @@ public void readEmptyBitBuffer() throws IOException
238238
jsonReader.close();
239239
}
240240

241+
@Test
242+
public void readEmptyBytes() throws IOException
243+
{
244+
final Reader reader = new StringReader("{\n"
245+
+ " \"value\": 13,\n"
246+
+ " \"nested\": {\n"
247+
+ " \"value\": 10,\n"
248+
+ " \"text\": \"nested\",\n"
249+
+ " \"externData\": {\n"
250+
+ " \"bitSize\": 0,\n"
251+
+ " \"buffer\": [\n"
252+
+ " ]\n"
253+
+ " },\n"
254+
+ " \"bytesData\": {\n"
255+
+ " \"buffer\": [\n"
256+
+ " ]\n"
257+
+ " },\n"
258+
+ " \"creatorEnum\": -1,\n"
259+
+ " \"creatorBitmask\": 1\n"
260+
+ " }\n"
261+
+ "}");
262+
263+
final JsonReader jsonReader = new JsonReader(reader);
264+
final Object zserioObject = jsonReader.read(CreatorObject.typeInfo());
265+
assertTrue(zserioObject != null);
266+
final CreatorObject creatorObject = (CreatorObject)zserioObject;
267+
268+
assertEquals(13, creatorObject.getValue());
269+
assertEquals(13, creatorObject.getNested().getParam());
270+
assertEquals(10, creatorObject.getNested().getValue());
271+
assertEquals("nested", creatorObject.getNested().getText());
272+
assertEquals(new BitBuffer(new byte[] {}), creatorObject.getNested().getExternData());
273+
assertArrayEquals(new byte[] {}, creatorObject.getNested().getBytesData());
274+
assertEquals(CreatorEnum.MinusOne, creatorObject.getNested().getCreatorEnum());
275+
assertEquals(CreatorBitmask.Values.READ, creatorObject.getNested().getCreatorBitmask());
276+
277+
jsonReader.close();
278+
}
279+
241280
@Test
242281
public void readStringifiedEnum() throws IOException
243282
{

compiler/extensions/python/runtime/src/zserio/json.py

+4-5
Original file line numberDiff line numberDiff line change
@@ -1040,6 +1040,7 @@ def end_object(self) -> None:
10401040
def begin_array(self) -> None:
10411041
if self._state == JsonReader._BytesAdapter._State.BEGIN_ARRAY_BUFFER:
10421042
self._state = JsonReader._BytesAdapter._State.VISIT_VALUE_BUFFER
1043+
self._buffer = bytearray()
10431044
else:
10441045
raise PythonRuntimeException("JsonReader: Unexpected begin array in bytes!")
10451046

@@ -1059,11 +1060,9 @@ def visit_key(self, key: str) -> None:
10591060
raise PythonRuntimeException(f"JsonReader: Unexpected key '{key}' in bytes!")
10601061

10611062
def visit_value(self, value: typing.Any) -> None:
1062-
if self._state == JsonReader._BytesAdapter._State.VISIT_VALUE_BUFFER and isinstance(value, int):
1063-
if self._buffer is None:
1064-
self._buffer = bytearray([value])
1065-
else:
1066-
self._buffer.append(value)
1063+
if (self._state == JsonReader._BytesAdapter._State.VISIT_VALUE_BUFFER and self._buffer is not None
1064+
and isinstance(value, int)):
1065+
self._buffer.append(value)
10671066
else:
10681067
raise PythonRuntimeException(f"JsonReader: Unexpected value '{value}' in bytes!")
10691068

compiler/extensions/python/runtime/tests/test_json.py

+36
Original file line numberDiff line numberDiff line change
@@ -1069,6 +1069,42 @@ def test_read_empty_bit_buffer(self):
10691069
self.assertEqual(CreatorEnum.ONE, creator_object.nested.creator_enum)
10701070
self.assertEqual(CreatorBitmask.Values.READ, creator_object.nested.creator_bitmask)
10711071

1072+
def test_read_empty_bytes(self):
1073+
text_io = io.StringIO(
1074+
"{\n" +
1075+
" \"value\": 13,\n" +
1076+
" \"nested\": {\n" +
1077+
" \"value\": 10,\n" +
1078+
" \"text\": \"nested\",\n" +
1079+
" \"externData\": {\n" +
1080+
" \"bitSize\": 0,\n" +
1081+
" \"buffer\": [\n" +
1082+
" ]\n" +
1083+
" },\n" +
1084+
" \"bytesData\": {\n" +
1085+
" \"buffer\": [\n" +
1086+
" ]\n" +
1087+
" },\n" +
1088+
" \"creatorEnum\": 0,\n" +
1089+
" \"creatorBitmask\": 1\n" +
1090+
" }\n" +
1091+
"}"
1092+
)
1093+
1094+
json_reader = JsonReader(text_io)
1095+
creator_object = json_reader.read(CreatorObject.type_info())
1096+
self.assertTrue(creator_object is not None)
1097+
self.assertTrue(isinstance(creator_object, CreatorObject))
1098+
1099+
self.assertEqual(13, creator_object.value)
1100+
self.assertEqual(13, creator_object.nested.param)
1101+
self.assertEqual(10, creator_object.nested.value)
1102+
self.assertEqual("nested", creator_object.nested.text)
1103+
self.assertEqual(BitBuffer(bytes()), creator_object.nested.extern_data)
1104+
self.assertEqual(bytes(), creator_object.nested.bytes_data)
1105+
self.assertEqual(CreatorEnum.ONE, creator_object.nested.creator_enum)
1106+
self.assertEqual(CreatorBitmask.Values.READ, creator_object.nested.creator_bitmask)
1107+
10721108
def test_read_stringified_enum(self):
10731109
self._check_read_stringified_enum("ONE", CreatorEnum.ONE)
10741110
self._check_read_stringified_enum("MinusOne", CreatorEnum.MINUS_ONE)

0 commit comments

Comments
 (0)