summaryrefslogtreecommitdiff
path: root/libgo/go/json/decode.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/json/decode.go')
-rw-r--r--libgo/go/json/decode.go71
1 files changed, 38 insertions, 33 deletions
diff --git a/libgo/go/json/decode.go b/libgo/go/json/decode.go
index b7129f9846a..31b15a400df 100644
--- a/libgo/go/json/decode.go
+++ b/libgo/go/json/decode.go
@@ -22,17 +22,20 @@ import (
// Unmarshal parses the JSON-encoded data and stores the result
// in the value pointed to by v.
//
-// Unmarshal traverses the value v recursively.
-// If an encountered value implements the Unmarshaler interface,
-// Unmarshal calls its UnmarshalJSON method with a well-formed
-// JSON encoding.
-//
-// Otherwise, Unmarshal uses the inverse of the encodings that
+// Unmarshal uses the inverse of the encodings that
// Marshal uses, allocating maps, slices, and pointers as necessary,
// with the following additional rules:
//
-// To unmarshal a JSON value into a nil interface value, the
-// type stored in the interface value is one of:
+// To unmarshal JSON into a pointer, Unmarshal first handles the case of
+// the JSON being the JSON literal null. In that case, Unmarshal sets
+// the pointer to nil. Otherwise, Unmarshal unmarshals the JSON into
+// the value pointed at by the pointer. If the pointer is nil, Unmarshal
+// allocates a new value for it to point to.
+//
+// To unmarshal JSON into an interface value, Unmarshal unmarshals
+// the JSON into the concrete value contained in the interface value.
+// If the interface value is nil, that is, has no concrete value stored in it,
+// Unmarshal stores one of these in the interface value:
//
// bool, for JSON booleans
// float64, for JSON numbers
@@ -250,8 +253,8 @@ func (d *decodeState) value(v reflect.Value) {
// indirect walks down v allocating pointers as needed,
// until it gets to a non-pointer.
// if it encounters an Unmarshaler, indirect stops and returns that.
-// if wantptr is true, indirect stops at the last pointer.
-func (d *decodeState) indirect(v reflect.Value, wantptr bool) (Unmarshaler, reflect.Value) {
+// if decodingNull is true, indirect stops at the last pointer so it can be set to nil.
+func (d *decodeState) indirect(v reflect.Value, decodingNull bool) (Unmarshaler, reflect.Value) {
// If v is a named type and is addressable,
// start with its address, so that if the type has pointer methods,
// we find them.
@@ -277,7 +280,7 @@ func (d *decodeState) indirect(v reflect.Value, wantptr bool) (Unmarshaler, refl
break
}
- if pv.Elem().Kind() != reflect.Ptr && wantptr && pv.CanSet() && !isUnmarshaler {
+ if pv.Elem().Kind() != reflect.Ptr && decodingNull && pv.CanSet() {
return nil, pv
}
if pv.IsNil() {
@@ -391,11 +394,6 @@ func (d *decodeState) array(v reflect.Value) {
}
}
-// matchName returns true if key should be written to a field named name.
-func matchName(key, name string) bool {
- return strings.ToLower(key) == strings.ToLower(name)
-}
-
// object consumes an object from d.data[d.off-1:], decoding into the value v.
// the first byte of the object ('{') has been read already.
func (d *decodeState) object(v reflect.Value) {
@@ -485,24 +483,31 @@ func (d *decodeState) object(v reflect.Value) {
var f reflect.StructField
var ok bool
st := sv.Type()
- // First try for field with that tag.
- if isValidTag(key) {
- for i := 0; i < sv.NumField(); i++ {
- f = st.Field(i)
- tagName, _ := parseTag(f.Tag.Get("json"))
- if tagName == key {
- ok = true
- break
- }
+ for i := 0; i < sv.NumField(); i++ {
+ sf := st.Field(i)
+ tag := sf.Tag.Get("json")
+ if tag == "-" {
+ // Pretend this field doesn't exist.
+ continue
+ }
+ // First, tag match
+ tagName, _ := parseTag(tag)
+ if tagName == key {
+ f = sf
+ ok = true
+ break // no better match possible
+ }
+ // Second, exact field name match
+ if sf.Name == key {
+ f = sf
+ ok = true
+ }
+ // Third, case-insensitive field name match,
+ // but only if a better match hasn't already been seen
+ if !ok && strings.EqualFold(sf.Name, key) {
+ f = sf
+ ok = true
}
- }
- if !ok {
- // Second, exact match.
- f, ok = st.FieldByName(key)
- }
- if !ok {
- // Third, case-insensitive match.
- f, ok = st.FieldByNameFunc(func(s string) bool { return matchName(key, s) })
}
// Extract value; name must be exported.