From 358027748bbc883d91efbc88cc1118526539acba Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Thu, 26 Feb 2026 10:23:15 +0300 Subject: [PATCH] json: fix decode transforms empty objects to empty strings (fixes #19791) --- vlib/json/json_primitives.c.v | 12 +++++++++--- vlib/json/tests/json_prim_type_validation_test.v | 13 +++++++++++++ vlib/v/gen/c/json.v | 2 +- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/vlib/json/json_primitives.c.v b/vlib/json/json_primitives.c.v index 97fec6cd5..081fd37be 100644 --- a/vlib/json/json_primitives.c.v +++ b/vlib/json/json_primitives.c.v @@ -24,6 +24,8 @@ pub struct C.cJSON { } fn C.cJSON_IsTrue(&C.cJSON) bool +fn C.cJSON_IsObject(&C.cJSON) bool +fn C.cJSON_IsArray(&C.cJSON) bool fn C.cJSON_CreateNumber(f64) &C.cJSON @@ -163,10 +165,14 @@ fn decode_string(root &C.cJSON) string { if isnil(root) { return '' } - if isnil(root.valuestring) { - return '' + if !isnil(root.valuestring) { + return unsafe { tos_clone(&u8(root.valuestring)) } // , _strlen(root.valuestring)) } - return unsafe { tos_clone(&u8(root.valuestring)) } // , _strlen(root.valuestring)) + // Object/array values can be stringified JSON payloads (e.g. `{}` from JSON.stringify()). + if C.cJSON_IsObject(root) || C.cJSON_IsArray(root) { + return json_print(root) + } + return '' } @[markused] diff --git a/vlib/json/tests/json_prim_type_validation_test.v b/vlib/json/tests/json_prim_type_validation_test.v index 3477ff0f1..b426a709f 100644 --- a/vlib/json/tests/json_prim_type_validation_test.v +++ b/vlib/json/tests/json_prim_type_validation_test.v @@ -8,6 +8,11 @@ struct MyStruct { active bool } +struct TestStructOne { + property_one string @[json: 'propertyOne'] + property_two string @[json: 'propertyTwo'] +} + fn test_main() { mut errors := 0 json.decode(MyStruct, '{ "name": 1}') or { @@ -24,4 +29,12 @@ fn test_main() { } res := json.decode(MyStruct, '{ "name": "John Doe", "age": "1"}') or { panic(err) } assert errors == 3 + assert res.name == 'John Doe' +} + +fn test_decode_object_into_string_field() { + payload := '{"propertyOne":"property_two should stay a regular string {}","propertyTwo":{}}' + res := json.decode(TestStructOne, payload) or { panic(err) } + assert res.property_one == 'property_two should stay a regular string {}' + assert res.property_two == '{}' } diff --git a/vlib/v/gen/c/json.v b/vlib/v/gen/c/json.v index f781a3d0f..d5c010280 100644 --- a/vlib/v/gen/c/json.v +++ b/vlib/v/gen/c/json.v @@ -645,7 +645,7 @@ fn (mut g Gen) gen_prim_type_validation(name string, typ ast.Type, tmp string, i type_check := if typ.is_int() || typ.is_float() { '${none_check}cJSON_IsNumber(jsonroot_${tmp}) || (cJSON_IsString(jsonroot_${tmp}) && strlen(jsonroot_${tmp}->valuestring))' } else if typ.is_string() { - '${none_check}cJSON_IsString(jsonroot_${tmp})' + '${none_check}(cJSON_IsString(jsonroot_${tmp}) || cJSON_IsObject(jsonroot_${tmp}) || cJSON_IsArray(jsonroot_${tmp}))' } else if typ.is_bool() { '${none_check}cJSON_IsBool(jsonroot_${tmp})' } else { -- 2.39.5