Commit 6e3f3af4 authored by Rick Arnold's avatar Rick Arnold Committed by Russ Cox

encoding/json: ignore unexported fields in Unmarshal

Go 1.0 behavior was to create an UnmarshalFieldError when a json value name matched an unexported field name. This error will no longer be created and the field will be skipped instead.

Fixes #4660.

R=adg, rsc, bradfitz
CC=golang-dev
https://golang.org/cl/7139049
parent 93d92d51
......@@ -106,6 +106,7 @@ func (e *UnmarshalTypeError) Error() string {
// An UnmarshalFieldError describes a JSON object key that
// led to an unexported (and therefore unwritable) struct field.
// (No longer used; kept for compatibility.)
type UnmarshalFieldError struct {
Key string
Type reflect.Type
......@@ -530,15 +531,6 @@ func (d *decodeState) object(v reflect.Value) {
}
subv = subv.Field(i)
}
} else {
// To give a good error, a quick scan for unexported fields in top level.
st := v.Type()
for i := 0; i < st.NumField(); i++ {
f := st.Field(i)
if f.PkgPath != "" && strings.EqualFold(f.Name, key) {
d.saveError(&UnmarshalFieldError{key, st, f})
}
}
}
}
......
......@@ -199,7 +199,7 @@ var unmarshalTests = []unmarshalTest{
{in: `"invalid: \uD834x\uDD1E"`, ptr: new(string), out: "invalid: \uFFFDx\uFFFD"},
{in: "null", ptr: new(interface{}), out: nil},
{in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &UnmarshalTypeError{"array", reflect.TypeOf("")}},
{in: `{"x": 1}`, ptr: new(tx), out: tx{}, err: &UnmarshalFieldError{"x", txType, txType.Field(0)}},
{in: `{"x": 1}`, ptr: new(tx), out: tx{}},
{in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: float64(1), F2: int32(2), F3: Number("3")}},
{in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: Number("1"), F2: int32(2), F3: Number("3")}, useNumber: true},
{in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(interface{}), out: ifaceNumAsFloat64},
......@@ -1064,3 +1064,25 @@ func TestUnmarshalTypeError(t *testing.T) {
}
}
}
// Test handling of unexported fields that should be ignored.
// Issue 4660
type unexportedFields struct {
Name string
m map[string]interface{} `json:"-"`
m2 map[string]interface{} `json:"abcd"`
}
func TestUnmarshalUnexported(t *testing.T) {
input := `{"Name": "Bob", "m": {"x": 123}, "m2": {"y": 456}, "abcd": {"z": 789}}`
want := &unexportedFields{Name: "Bob"}
out := &unexportedFields{}
err := Unmarshal([]byte(input), out)
if err != nil {
t.Errorf("got error %v, expected nil", err)
}
if !reflect.DeepEqual(out, want) {
t.Errorf("got %q, want %q", out, want)
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment