You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The encoder in x.json2 ignores the @[json_null] field attribute. With the legacy json (cJSON) encoder, an Option field annotated with @[json_null] is emitted as "field":null instead of being skipped when the value is none. x.json2 always omits none fields and provides no way to opt-in to writing JSON null.
V code
importx.json2structFoo {
name ?string @[json_null]
age ?int @[json_null]
other2?string @[json_null]
}
fnmain() {
println(json2.encode(Foo{}))
}
C backend result
// Encoder writes nothing for `none` Option fields — the @[json_null]// attribute is never read in the encoder.// Output: {}
Reproduction Steps
importx.json2structBar {
name ?string @[json_null]
}
structFoo {
name ?string @[json_null]
age ?int @[json_null]
text ?string
other ?Bar
other2?Bar @[json_null]
}
fntest_json_null_attribute() {
assert json2.encode(Foo{}) =='{"name":null,"age":null,"other2":null}'assert json2.encode(Foo{ name: '' }) =='{"name":"","age":null,"other2":null}'assert json2.encode(Foo{ age: 10 }) =='{"name":null,"age":10,"other2":null}'assert json2.encode(Foo{
age: 10
other2: Bar{
name: none
}
}) =='{"name":null,"age":10,"other2":{"name":null}}'
}
Expected Behavior
PASS test_json_null_attribute
Current Behavior
> assert json2.encode(Foo{}) == '{"name":null,"age":null,"other2":null}'
Left value (len: 2): `{}`
Right value (len: 38): `{"name":null,"age":null,"other2":null}`
Possible Solution
In the struct encoder loop, when iterating fields with $for field in T.fields and detecting field.typ is $option:
If the option is none, check whether 'json_null' in field.attrs.
If yes, emit "<key>":null, instead of skipping the field.
Apply the same rule to embedded option struct values (the other2 ?Bar @[json_null] case in the failing test) and to nested option struct fields (Bar{ name: none } → {"name":null}).
Cache this attribute lookup in cached_field_infos by adding an is_json_null bool field to EncoderFieldInfo so the comptime cost is paid once per type.
Additional Information/Context
This is feature parity with the cJSON json_is_null_attr test, which already passes against the cJSON-based json module. Without this attribute, downstream APIs that distinguish "absent" vs "null" (e.g. JSON Merge Patch, Stripe API style) cannot be expressed in x.json2.
V version
V 0.5.1 1b3385cc34ff783e793d1a26a8ec5be587c80fe0.40b3711
Environment details (OS name and version, etc.)
|V full version |V 0.5.1 1b3385cc34ff783e793d1a26a8ec5be587c80fe0.40b3711
|:-------------------|:-------------------
|OS |linux, Ubuntu 24.04 LTS
|Processor |16 cpus, 64bit, little endian, AMD Ryzen 7 5800H with Radeon Graphics
|Memory |8.17GB/30.7GB
| |
|V executable |/home/hitalo/Documents/v/v
|V last modified time|2026-04-18 09:18:00
| |
|V home dir |OK, value: /home/hitalo/Documents/v
|VMODULES |OK, value: /home/hitalo/.vmodules
|VTMP |OK, value: /tmp/v_1000
|Current working dir |OK, value: /home/hitalo/Documents/v
| |
|Git version |git version 2.43.0
|V git status |0.5.1-1006-g40b3711b-dirty
|.git/config present |true
| |
|cc version |cc (GCC) 14.2.0
|gcc version |gcc (GCC) 14.2.0
|clang version |Ubuntu clang version 18.1.3 (1)
|tcc version |tcc version 0.9.28rc 2025-02-13 HEAD@f8bd136d (x86_64 Linux)
|tcc git status |thirdparty-linux-amd64 696c1d84
|emcc version |emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.6 ()
|glibc version |ldd (Ubuntu GLIBC 2.39-0ubuntu8.3) 2.39
Note
You can use the 👍 reaction to increase the issue's priority for developers.
Please note that only the 👍 reaction to the issue itself counts as a vote.
Other reactions and those to comments will not be taken into account.
Describe the bug
The encoder in
x.json2ignores the@[json_null]field attribute. With the legacyjson(cJSON) encoder, anOptionfield annotated with@[json_null]is emitted as"field":nullinstead of being skipped when the value isnone.x.json2always omitsnonefields and provides no way to opt-in to writing JSONnull.V code
C backend result
Reproduction Steps
Expected Behavior
Current Behavior
Possible Solution
In the struct encoder loop, when iterating fields with
$for field in T.fieldsand detectingfield.typ is $option:none, check whether'json_null' in field.attrs."<key>":null,instead of skipping the field.other2 ?Bar @[json_null]case in the failing test) and to nested option struct fields (Bar{ name: none }→{"name":null}).Cache this attribute lookup in
cached_field_infosby adding anis_json_null boolfield toEncoderFieldInfoso the comptime cost is paid once per type.Additional Information/Context
This is feature parity with the cJSON
json_is_null_attrtest, which already passes against the cJSON-basedjsonmodule. Without this attribute, downstream APIs that distinguish "absent" vs "null" (e.g. JSON Merge Patch, Stripe API style) cannot be expressed inx.json2.V version
Environment details (OS name and version, etc.)
Note
You can use the 👍 reaction to increase the issue's priority for developers.
Please note that only the 👍 reaction to the issue itself counts as a vote.
Other reactions and those to comments will not be taken into account.