json: fix json decode with missing map type field (#14678)

master
yuyi 2022-06-05 01:27:11 +08:00 committed by GitHub
parent d71fd04c81
commit 5d429140a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 43 additions and 56 deletions

View File

@ -425,6 +425,13 @@ fn test_decode_null_object() ? {
assert '$info.maps' == '{}'
}
fn test_decode_missing_maps_field() ? {
info := json.decode(Info, '{"id": 22, "items": null}')?
assert info.id == 22
assert '$info.items' == '[]'
assert '$info.maps' == '{}'
}
struct Foo2 {
name string
}

View File

@ -53,22 +53,11 @@ fn (mut g Gen) gen_jsons() {
mut init_styp := '$styp res'
if sym.kind == .struct_ {
mut skips := 0
info := sym.info as ast.Struct
for field in info.fields {
for attr in field.attrs {
if attr.name == 'skip' {
skips++
}
}
}
if skips > 0 {
init_styp += ' = '
init_styp += g.expr_string(ast.Expr(ast.StructInit{
typ: utyp
typ_str: styp
}))
}
init_styp += ' = '
init_styp += g.expr_string(ast.Expr(ast.StructInit{
typ: utyp
typ_str: styp
}))
}
dec.writeln('
@ -398,41 +387,35 @@ fn (mut g Gen) gen_struct_enc_dec(type_info ast.TypeInfo, styp string, mut enc s
if is_js_prim(field_type) {
tmp := g.new_tmp_var()
gen_js_get(styp, tmp, name, mut dec, is_required)
if field.has_default_expr {
dec.writeln('\tif (jsonroot_$tmp) {')
}
dec.writeln('\tres.${c_name(field.name)} = $dec_name (jsonroot_$tmp);')
dec.writeln('\tif (jsonroot_$tmp) {')
dec.writeln('\t\tres.${c_name(field.name)} = ${dec_name}(jsonroot_$tmp);')
if field.has_default_expr {
dec.writeln('\t} else {')
dec.writeln('\tres.${c_name(field.name)} = ${g.expr_string(field.default_expr)};')
dec.writeln('\t}')
dec.writeln('\t\tres.${c_name(field.name)} = ${g.expr_string(field.default_expr)};')
}
dec.writeln('\t}')
} else if field_sym.kind == .enum_ {
tmp := g.new_tmp_var()
gen_js_get(styp, tmp, name, mut dec, is_required)
if field.has_default_expr {
dec.writeln('\tif (jsonroot_$tmp) {')
}
dec.writeln('\tres.${c_name(field.name)} = json__decode_u64(jsonroot_$tmp);')
dec.writeln('\tif (jsonroot_$tmp) {')
dec.writeln('\t\tres.${c_name(field.name)} = json__decode_u64(jsonroot_$tmp);')
if field.has_default_expr {
dec.writeln('\t} else {')
dec.writeln('\tres.${c_name(field.name)} = ${g.expr_string(field.default_expr)};')
dec.writeln('\t}')
dec.writeln('\t\tres.${c_name(field.name)} = ${g.expr_string(field.default_expr)};')
}
dec.writeln('\t}')
} else if field_sym.name == 'time.Time' {
// time struct requires special treatment
// it has to be decoded from a unix timestamp number
tmp := g.new_tmp_var()
gen_js_get(styp, tmp, name, mut dec, is_required)
if field.has_default_expr {
dec.writeln('\tif (jsonroot_$tmp) {')
}
dec.writeln('\tres.${c_name(field.name)} = time__unix(json__decode_u64(jsonroot_$tmp));')
dec.writeln('\tif (jsonroot_$tmp) {')
dec.writeln('\t\tres.${c_name(field.name)} = time__unix(json__decode_u64(jsonroot_$tmp));')
if field.has_default_expr {
dec.writeln('\t} else {')
dec.writeln('\tres.${c_name(field.name)} = ${g.expr_string(field.default_expr)};')
dec.writeln('\t}')
dec.writeln('\t\tres.${c_name(field.name)} = ${g.expr_string(field.default_expr)};')
}
dec.writeln('\t}')
} else if field_sym.kind == .alias {
alias := field_sym.info as ast.Alias
parent_type := g.typ(alias.parent_type)
@ -440,41 +423,35 @@ fn (mut g Gen) gen_struct_enc_dec(type_info ast.TypeInfo, styp string, mut enc s
if is_js_prim(parent_type) {
tmp := g.new_tmp_var()
gen_js_get(styp, tmp, name, mut dec, is_required)
if field.has_default_expr {
dec.writeln('\tif (jsonroot_$tmp) {')
}
dec.writeln('\tres.${c_name(field.name)} = $parent_dec_name (jsonroot_$tmp);')
dec.writeln('\tif (jsonroot_$tmp) {')
dec.writeln('\t\tres.${c_name(field.name)} = $parent_dec_name (jsonroot_$tmp);')
if field.has_default_expr {
dec.writeln('\t} else {')
dec.writeln('\tres.${c_name(field.name)} = ${g.expr_string(field.default_expr)};')
dec.writeln('\t}')
dec.writeln('\t\tres.${c_name(field.name)} = ${g.expr_string(field.default_expr)};')
}
dec.writeln('\t}')
} else {
g.gen_json_for_type(field.typ)
tmp := g.new_tmp_var()
gen_js_get_opt(dec_name, field_type, styp, tmp, name, mut dec, is_required)
if field.has_default_expr {
dec.writeln('\tif (jsonroot_$tmp) {')
}
dec.writeln('\tres.${c_name(field.name)} = *($field_type*) ${tmp}.data;')
dec.writeln('\tif (jsonroot_$tmp) {')
dec.writeln('\t\tres.${c_name(field.name)} = *($field_type*) ${tmp}.data;')
if field.has_default_expr {
dec.writeln('\t} else {')
dec.writeln('\tres.${c_name(field.name)} = ${g.expr_string(field.default_expr)};')
dec.writeln('\t}')
dec.writeln('\t\tres.${c_name(field.name)} = ${g.expr_string(field.default_expr)};')
}
dec.writeln('\t}')
}
} else {
tmp := g.new_tmp_var()
gen_js_get_opt(dec_name, field_type, styp, tmp, name, mut dec, is_required)
if field.has_default_expr {
dec.writeln('\tif (jsonroot_$tmp) {')
}
dec.writeln('\tres.${c_name(field.name)} = *($field_type*) ${tmp}.data;')
dec.writeln('\tif (jsonroot_$tmp) {')
dec.writeln('\t\tres.${c_name(field.name)} = *($field_type*) ${tmp}.data;')
if field.has_default_expr {
dec.writeln('\t} else {')
dec.writeln('\tres.${c_name(field.name)} = ${g.expr_string(field.default_expr)};')
dec.writeln('\t}')
dec.writeln('\t\tres.${c_name(field.name)} = ${g.expr_string(field.default_expr)};')
}
dec.writeln('\t}')
}
}
// Encoding
@ -505,7 +482,7 @@ fn (mut g Gen) gen_struct_enc_dec(type_info ast.TypeInfo, styp string, mut enc s
fn gen_js_get(styp string, tmp string, name string, mut dec strings.Builder, is_required bool) {
dec.writeln('\tcJSON *jsonroot_$tmp = js_get(root, "$name");')
if is_required {
dec.writeln('\tif(jsonroot_$tmp == 0) {')
dec.writeln('\tif (jsonroot_$tmp == 0) {')
dec.writeln('\t\treturn (${option_name}_$styp){ .state = 2, .err = _v_error(_SLIT("expected field \'$name\' is missing")), .data = {0} };')
dec.writeln('\t}')
}
@ -513,9 +490,12 @@ fn gen_js_get(styp string, tmp string, name string, mut dec strings.Builder, is_
fn gen_js_get_opt(dec_name string, field_type string, styp string, tmp string, name string, mut dec strings.Builder, is_required bool) {
gen_js_get(styp, tmp, name, mut dec, is_required)
dec.writeln('\t${option_name}_$field_type $tmp = $dec_name (jsonroot_$tmp);')
dec.writeln('\tif(${tmp}.state != 0) {')
dec.writeln('\t\treturn (${option_name}_$styp){ .state = ${tmp}.state, .err = ${tmp}.err, .data = {0} };')
dec.writeln('\t${option_name}_$field_type $tmp;')
dec.writeln('\tif (jsonroot_$tmp) {')
dec.writeln('\t\t$tmp = ${dec_name}(jsonroot_$tmp);')
dec.writeln('\t\tif (${tmp}.state != 0) {')
dec.writeln('\t\t\treturn (${option_name}_$styp){ .state = ${tmp}.state, .err = ${tmp}.err, .data = {0} };')
dec.writeln('\t\t}')
dec.writeln('\t}')
}