aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2010-04-27 10:24:00 -0700
committerRuss Cox <rsc@golang.org>2010-04-27 10:24:00 -0700
commitbec40ba516e2c8ff4cbcd0eaa3dc84a03c230289 (patch)
treedfcfb493c4624718c2fb954e87004f9d4428e359
parentcc62bed075ed2a7d1f65f2d65e55af1ffab7cdba (diff)
downloadgo-bec40ba516e2c8ff4cbcd0eaa3dc84a03c230289.tar.gz
go-bec40ba516e2c8ff4cbcd0eaa3dc84a03c230289.zip
json: preserve field name case by default
This matches the old JSON package behavior. All lowercase names are not as standard as I believed, and it seems less surprising to need to write type T struct { Field string "field" } to get lower case (behavior after this CL) than it does to need to write type T struct { Field string "Field" } to preserve the case (behavior before this CL). Also test and fix unmarshal into non-nil interface value or pointer. Fixes #744. R=r CC=golang-dev https://golang.org/cl/1013041
-rw-r--r--src/pkg/json/decode.go20
-rw-r--r--src/pkg/json/decode_test.go266
-rw-r--r--src/pkg/json/encode.go5
3 files changed, 164 insertions, 127 deletions
diff --git a/src/pkg/json/decode.go b/src/pkg/json/decode.go
index d37f609233..e8da35acef 100644
--- a/src/pkg/json/decode.go
+++ b/src/pkg/json/decode.go
@@ -20,7 +20,7 @@ import (
)
// Unmarshal parses the JSON-encoded data and stores the result
-// in the value pointed at by v.
+// in the value pointed to by v.
//
// Unmarshal traverses the value v recursively.
// If an encountered value implements the Unmarshaler interface,
@@ -247,6 +247,10 @@ func (d *decodeState) indirect(v reflect.Value, wantptr bool) (Unmarshaler, refl
_, isUnmarshaler = v.Interface().(Unmarshaler)
}
+ if iv, ok := v.(*reflect.InterfaceValue); ok && !iv.IsNil() {
+ v = iv.Elem()
+ continue
+ }
pv, ok := v.(*reflect.PtrValue)
if !ok {
break
@@ -255,7 +259,9 @@ func (d *decodeState) indirect(v reflect.Value, wantptr bool) (Unmarshaler, refl
if !isptrptr && wantptr && !isUnmarshaler {
return nil, pv
}
- pv.PointTo(reflect.MakeZero(pv.Type().(*reflect.PtrType).Elem()))
+ if pv.IsNil() {
+ pv.PointTo(reflect.MakeZero(pv.Type().(*reflect.PtrType).Elem()))
+ }
if isUnmarshaler {
// Using v.Interface().(Unmarshaler)
// here means that we have to use a pointer
@@ -436,11 +442,12 @@ func (d *decodeState) object(v reflect.Value) {
d.error(errPhase)
}
- // Figure out
+ // Figure out field corresponding to key.
var subv reflect.Value
if mv != nil {
subv = reflect.MakeZero(mv.Type().(*reflect.MapType).Elem())
} else {
+ // First try for field with that tag.
for i := 0; i < sv.NumField(); i++ {
f := sv.Type().(*reflect.StructType).Field(i)
if f.Tag == key {
@@ -449,7 +456,12 @@ func (d *decodeState) object(v reflect.Value) {
}
}
if subv == nil {
- subv = sv.FieldByNameFunc(func(s string) bool { return matchName(key, s) })
+ // Second, exact match.
+ subv = sv.FieldByName(key)
+ if subv == nil {
+ // Third, case-insensitive match.
+ subv = sv.FieldByNameFunc(func(s string) bool { return matchName(key, s) })
+ }
}
}
diff --git a/src/pkg/json/decode_test.go b/src/pkg/json/decode_test.go
index 288bb1b404..9e7d810cee 100644
--- a/src/pkg/json/decode_test.go
+++ b/src/pkg/json/decode_test.go
@@ -104,6 +104,32 @@ func TestUnmarshalMarshal(t *testing.T) {
}
}
+type Xint struct {
+ X int
+}
+
+func TestUnmarshalInterface(t *testing.T) {
+ var xint Xint
+ var i interface{} = &xint
+ if err := Unmarshal([]byte(`{"X":1}`), &i); err != nil {
+ t.Fatalf("Unmarshal: %v", err)
+ }
+ if xint.X != 1 {
+ t.Fatalf("Did not write to xint")
+ }
+}
+
+func TestUnmarshalPtrPtr(t *testing.T) {
+ var xint Xint
+ pxint := &xint
+ if err := Unmarshal([]byte(`{"X":1}`), &pxint); err != nil {
+ t.Fatalf("Unmarshal: %v", err)
+ }
+ if xint.X != 1 {
+ t.Fatalf("Did not write to xint")
+ }
+}
+
func noSpace(c int) int {
if isSpace(c) {
return -1
@@ -243,185 +269,185 @@ var pallValue = All{
}
var allValueIndent = `{
- "bool": true,
- "int": 2,
- "int8": 3,
- "int16": 4,
- "int32": 5,
- "int64": 6,
- "uint": 7,
- "uint8": 8,
- "uint16": 9,
- "uint32": 10,
- "uint64": 11,
- "uintptr": 12,
- "float": 13.1,
- "float32": 14.1,
- "float64": 15.1,
+ "Bool": true,
+ "Int": 2,
+ "Int8": 3,
+ "Int16": 4,
+ "Int32": 5,
+ "Int64": 6,
+ "Uint": 7,
+ "Uint8": 8,
+ "Uint16": 9,
+ "Uint32": 10,
+ "Uint64": 11,
+ "Uintptr": 12,
+ "Float": 13.1,
+ "Float32": 14.1,
+ "Float64": 15.1,
"bar": "foo",
- "pbool": null,
- "pint": null,
- "pint8": null,
- "pint16": null,
- "pint32": null,
- "pint64": null,
- "puint": null,
- "puint8": null,
- "puint16": null,
- "puint32": null,
- "puint64": null,
- "puintptr": null,
- "pfloat": null,
- "pfloat32": null,
- "pfloat64": null,
- "string": "16",
- "pstring": null,
- "map": {
+ "PBool": null,
+ "PInt": null,
+ "PInt8": null,
+ "PInt16": null,
+ "PInt32": null,
+ "PInt64": null,
+ "PUint": null,
+ "PUint8": null,
+ "PUint16": null,
+ "PUint32": null,
+ "PUint64": null,
+ "PUintptr": null,
+ "PFloat": null,
+ "PFloat32": null,
+ "PFloat64": null,
+ "String": "16",
+ "PString": null,
+ "Map": {
"17": {
- "tag": "tag17"
+ "Tag": "tag17"
},
"18": {
- "tag": "tag18"
+ "Tag": "tag18"
}
},
- "mapp": {
+ "MapP": {
"19": {
- "tag": "tag19"
+ "Tag": "tag19"
},
"20": null
},
- "pmap": null,
- "pmapp": null,
- "emptymap": {},
- "nilmap": null,
- "slice": [
+ "PMap": null,
+ "PMapP": null,
+ "EmptyMap": {},
+ "NilMap": null,
+ "Slice": [
{
- "tag": "tag20"
+ "Tag": "tag20"
},
{
- "tag": "tag21"
+ "Tag": "tag21"
}
],
- "slicep": [
+ "SliceP": [
{
- "tag": "tag22"
+ "Tag": "tag22"
},
null,
{
- "tag": "tag23"
+ "Tag": "tag23"
}
],
- "pslice": null,
- "pslicep": null,
- "emptyslice": [],
- "nilslice": [],
- "stringslice": [
+ "PSlice": null,
+ "PSliceP": null,
+ "EmptySlice": [],
+ "NilSlice": [],
+ "StringSlice": [
"str24",
"str25",
"str26"
],
- "byteslice": [
+ "ByteSlice": [
27,
28,
29
],
- "small": {
- "tag": "tag30"
+ "Small": {
+ "Tag": "tag30"
},
- "psmall": {
- "tag": "tag31"
+ "PSmall": {
+ "Tag": "tag31"
},
- "ppsmall": null,
- "interface": 5.2,
- "pinterface": null
+ "PPSmall": null,
+ "Interface": 5.2,
+ "PInterface": null
}`
var allValueCompact = strings.Map(noSpace, allValueIndent)
var pallValueIndent = `{
- "bool": false,
- "int": 0,
- "int8": 0,
- "int16": 0,
- "int32": 0,
- "int64": 0,
- "uint": 0,
- "uint8": 0,
- "uint16": 0,
- "uint32": 0,
- "uint64": 0,
- "uintptr": 0,
- "float": 0,
- "float32": 0,
- "float64": 0,
+ "Bool": false,
+ "Int": 0,
+ "Int8": 0,
+ "Int16": 0,
+ "Int32": 0,
+ "Int64": 0,
+ "Uint": 0,
+ "Uint8": 0,
+ "Uint16": 0,
+ "Uint32": 0,
+ "Uint64": 0,
+ "Uintptr": 0,
+ "Float": 0,
+ "Float32": 0,
+ "Float64": 0,
"bar": "",
- "pbool": true,
- "pint": 2,
- "pint8": 3,
- "pint16": 4,
- "pint32": 5,
- "pint64": 6,
- "puint": 7,
- "puint8": 8,
- "puint16": 9,
- "puint32": 10,
- "puint64": 11,
- "puintptr": 12,
- "pfloat": 13.1,
- "pfloat32": 14.1,
- "pfloat64": 15.1,
- "string": "",
- "pstring": "16",
- "map": null,
- "mapp": null,
- "pmap": {
+ "PBool": true,
+ "PInt": 2,
+ "PInt8": 3,
+ "PInt16": 4,
+ "PInt32": 5,
+ "PInt64": 6,
+ "PUint": 7,
+ "PUint8": 8,
+ "PUint16": 9,
+ "PUint32": 10,
+ "PUint64": 11,
+ "PUintptr": 12,
+ "PFloat": 13.1,
+ "PFloat32": 14.1,
+ "PFloat64": 15.1,
+ "String": "",
+ "PString": "16",
+ "Map": null,
+ "MapP": null,
+ "PMap": {
"17": {
- "tag": "tag17"
+ "Tag": "tag17"
},
"18": {
- "tag": "tag18"
+ "Tag": "tag18"
}
},
- "pmapp": {
+ "PMapP": {
"19": {
- "tag": "tag19"
+ "Tag": "tag19"
},
"20": null
},
- "emptymap": null,
- "nilmap": null,
- "slice": [],
- "slicep": [],
- "pslice": [
+ "EmptyMap": null,
+ "NilMap": null,
+ "Slice": [],
+ "SliceP": [],
+ "PSlice": [
{
- "tag": "tag20"
+ "Tag": "tag20"
},
{
- "tag": "tag21"
+ "Tag": "tag21"
}
],
- "pslicep": [
+ "PSliceP": [
{
- "tag": "tag22"
+ "Tag": "tag22"
},
null,
{
- "tag": "tag23"
+ "Tag": "tag23"
}
],
- "emptyslice": [],
- "nilslice": [],
- "stringslice": [],
- "byteslice": [],
- "small": {
- "tag": ""
+ "EmptySlice": [],
+ "NilSlice": [],
+ "StringSlice": [],
+ "ByteSlice": [],
+ "Small": {
+ "Tag": ""
},
- "psmall": null,
- "ppsmall": {
- "tag": "tag31"
+ "PSmall": null,
+ "PPSmall": {
+ "Tag": "tag31"
},
- "interface": null,
- "pinterface": 5.2
+ "Interface": null,
+ "PInterface": 5.2
}`
var pallValueCompact = strings.Map(noSpace, pallValueIndent)
diff --git a/src/pkg/json/encode.go b/src/pkg/json/encode.go
index 1de22086d2..839657c361 100644
--- a/src/pkg/json/encode.go
+++ b/src/pkg/json/encode.go
@@ -11,7 +11,6 @@ import (
"runtime"
"sort"
"strconv"
- "strings"
)
// Marshal returns the JSON encoding of v.
@@ -40,7 +39,7 @@ import (
// The map's key type must be string; the object keys are used directly
// as map keys.
//
-// Pointer values encode as the value pointed at.
+// Pointer values encode as the value pointed to.
// A nil pointer encodes as the null JSON object.
//
// Interface values encode as the value contained in the interface.
@@ -202,7 +201,7 @@ func (e *encodeState) reflectValue(v reflect.Value) {
if f.Tag != "" {
e.string(f.Tag)
} else {
- e.string(strings.ToLower(f.Name))
+ e.string(f.Name)
}
e.WriteByte(':')
e.reflectValue(v.Field(i))