Allow empty maps for required map fields (issue #256)

As reported in issue #256, currently, an empty map is unmarshalled into nil by easyjson
If a field is marked "required" or "!omitempty", then the empty map is a valid input and
we should unmarshal it into an empty map.

Similar logic for marshalling.

This change is to fix the behavior
This commit is contained in:
Aravind Gopalan
2019-11-21 18:03:16 -08:00
parent 6c0755d89d
commit d6768890ec
4 changed files with 39 additions and 4 deletions
+1
View File
@@ -3,3 +3,4 @@
*.iml
.idea
*.swp
bin/*
+9 -4
View File
@@ -228,16 +228,21 @@ func (g *Generator) genTypeDecoderNoCheck(t reflect.Type, out string, tags field
} // else assume the caller knows what they are doing and that the custom unmarshaler performs the translation from string or integer keys to the key type
elem := t.Elem()
tmpVar := g.uniqueVarName()
keepEmpty := tags.required || tags.noOmitEmpty || (!g.omitEmpty && !tags.omitEmpty)
fmt.Fprintln(g.out, ws+"if in.IsNull() {")
fmt.Fprintln(g.out, ws+" in.Skip()")
fmt.Fprintln(g.out, ws+"} else {")
fmt.Fprintln(g.out, ws+" in.Delim('{')")
fmt.Fprintln(g.out, ws+" if !in.IsDelim('}') {")
if !keepEmpty {
fmt.Fprintln(g.out, ws+" if !in.IsDelim('}') {")
}
fmt.Fprintln(g.out, ws+" "+out+" = make("+g.getType(t)+")")
fmt.Fprintln(g.out, ws+" } else {")
fmt.Fprintln(g.out, ws+" "+out+" = nil")
fmt.Fprintln(g.out, ws+" }")
if !keepEmpty {
fmt.Fprintln(g.out, ws+" } else {")
fmt.Fprintln(g.out, ws+" "+out+" = nil")
fmt.Fprintln(g.out, ws+" }")
}
fmt.Fprintln(g.out, ws+" for !in.IsDelim('}') {")
// NOTE: extra check for TextUnmarshaler. It overrides default methods.
+6
View File
@@ -678,6 +678,12 @@ type RequiredOptionalStruct struct {
Lastname string `json:"last_name"`
}
type RequiredOptionalMap struct {
ReqMap map[int]string `json:"req_map,required"`
OmitEmptyMap map[int]string `json:"oe_map,omitempty"`
NoOmitEmptyMap map[int]string `json:"noe_map,!omitempty"`
}
//easyjson:json
type EncodingFlagsTestMap struct {
F map[string]string
+23
View File
@@ -2,6 +2,7 @@ package tests
import (
"fmt"
"reflect"
"testing"
)
@@ -26,3 +27,25 @@ func TestRequiredField(t *testing.T) {
}
}
}
func TestRequiredOptionalMap(t *testing.T) {
baseJson := `{"req_map":{}, "oe_map":{}, "noe_map":{}, "oe_slice":[]}`
wantDecoding := RequiredOptionalMap{MapIntString{}, nil, MapIntString{}}
var v RequiredOptionalMap
if err := v.UnmarshalJSON([]byte(baseJson)); err != nil {
t.Errorf("%s. UnmarshalJSON didn't expect error: %v", baseJson, err)
}
if !reflect.DeepEqual(v, wantDecoding) {
t.Errorf("%s. UnmarshalJSON expected to gen: %v. got: %v", baseJson, wantDecoding, v)
}
baseStruct := RequiredOptionalMap{MapIntString{}, MapIntString{}, MapIntString{}}
wantJson := `{"req_map":{},"noe_map":{}}`
data, err := baseStruct.MarshalJSON()
if err != nil {
t.Errorf("MarshalJSON didn't expect error: %v on %v", err, data)
} else if string(data) != wantJson {
t.Errorf("%v. MarshalJSON wanted: %s got %s", baseStruct, wantJson, string(data))
}
}