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' == '{}' 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 { struct Foo2 {
name string name string
} }

View File

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