func (e *encodeState) reflectValue(v reflect.Value) { if v == nil { e.WriteString("null") return } if j, ok := v.Interface().(Marshaler); ok { b, err := j.MarshalXML() if err == nil { // copy XML into buffer, checking validity. err = Compact(&e.Buffer, b) } if err != nil { e.error(&MarshalerError{v.Type(), err}) } return } switch v := v.(type) { case *reflect.BoolValue: x := v.Get() if x { e.WriteString("true") } else { e.WriteString("false") } case *reflect.IntValue: e.WriteString(strconv.Itoa64(v.Get())) case *reflect.UintValue: e.WriteString(strconv.Uitoa64(v.Get())) case *reflect.FloatValue: e.WriteString(strconv.FtoaN(v.Get(), 'g', -1, v.Type().Bits())) case *reflect.StringValue: e.WriteString(v.Get()) case *reflect.StructValue: t := v.Type().(*reflect.StructType) e.openTag(t.Name()) n := v.NumField() for i := 0; i < n; i++ { f := t.Field(i) if f.Tag != "" { e.openTag(f.Tag) e.reflectValue(v.Field(i)) e.closeTag(f.Tag) } else { e.openTag(f.Name) e.reflectValue(v.Field(i)) e.closeTag(f.Name) } } e.closeTag(t.Name()) case *reflect.MapValue: if _, ok := v.Type().(*reflect.MapType).Key().(*reflect.StringType); !ok { e.error(&UnsupportedTypeError{v.Type()}) } if v.IsNil() { e.WriteString("null") break } e.WriteByte('{') var sv stringValues = v.Keys() sort.Sort(sv) for i, k := range sv { if i > 0 { e.WriteByte(',') } e.string(k.(*reflect.StringValue).Get()) e.WriteByte(':') e.reflectValue(v.Elem(k)) } e.WriteByte('}') case reflect.ArrayOrSliceValue: e.WriteByte('[') n := v.Len() for i := 0; i < n; i++ { if i > 0 { e.WriteByte(',') } e.reflectValue(v.Elem(i)) } e.WriteByte(']') case interfaceOrPtrValue: if v.IsNil() { e.WriteString("null") return } e.reflectValue(v.Elem()) default: e.error(&UnsupportedTypeError{v.Type()}) } return }
func (e *encodeState) reflectValue(v reflect.Value) { if !v.IsValid() { e.WriteString("null") return } if j, ok := v.Interface().(Marshaler); ok { b, err := j.MarshalJSON() if err == nil { // copy JSON into buffer, checking validity. err = Compact(&e.Buffer, b) } if err != nil { e.error(&MarshalerError{v.Type(), err}) } return } switch v.Kind() { case reflect.Bool: x := v.Bool() if x { e.WriteString("true") } else { e.WriteString("false") } case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: e.WriteString(strconv.Itoa64(v.Int())) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: e.WriteString(strconv.Uitoa64(v.Uint())) case reflect.Float32, reflect.Float64: e.WriteString(strconv.FtoaN(v.Float(), 'g', -1, v.Type().Bits())) case reflect.String: e.string(v.String()) case reflect.Struct: e.WriteByte('{') t := v.Type() n := v.NumField() first := true for i := 0; i < n; i++ { f := t.Field(i) if f.PkgPath != "" { continue } if first { first = false } else { e.WriteByte(',') } if isValidTag(f.Tag) { e.string(f.Tag) } else { e.string(f.Name) } e.WriteByte(':') e.reflectValue(v.Field(i)) } e.WriteByte('}') case reflect.Map: if v.Type().Key().Kind() != reflect.String { e.error(&UnsupportedTypeError{v.Type()}) } if v.IsNil() { e.WriteString("null") break } e.WriteByte('{') var sv stringValues = v.MapKeys() sort.Sort(sv) for i, k := range sv { if i > 0 { e.WriteByte(',') } e.string(k.String()) e.WriteByte(':') e.reflectValue(v.MapIndex(k)) } e.WriteByte('}') case reflect.Array, reflect.Slice: if v.Type() == byteSliceType { e.WriteByte('"') s := v.Interface().([]byte) if len(s) < 1024 { // for small buffers, using Encode directly is much faster. dst := make([]byte, base64.StdEncoding.EncodedLen(len(s))) base64.StdEncoding.Encode(dst, s) e.Write(dst) } else { // for large buffers, avoid unnecessary extra temporary // buffer space. enc := base64.NewEncoder(base64.StdEncoding, e) enc.Write(s) enc.Close() } e.WriteByte('"') break } e.WriteByte('[') n := v.Len() for i := 0; i < n; i++ { if i > 0 { e.WriteByte(',') } e.reflectValue(v.Index(i)) } e.WriteByte(']') case reflect.Interface, reflect.Ptr: if v.IsNil() { e.WriteString("null") return } e.reflectValue(v.Elem()) default: e.error(&UnsupportedTypeError{v.Type()}) } return }
// reflectValueQuoted writes the value in v to the output. // If quoted is true, the serialization is wrapped in a JSON string. func (e *encodeState) reflectValueQuoted(v reflect.Value, quoted bool) { if !v.IsValid() { e.WriteString("null") return } if j, ok := v.Interface().(Marshaler); ok && (v.Kind() != reflect.Ptr || !v.IsNil()) { b, err := j.MarshalJSON() if err == nil { // copy JSON into buffer, checking validity. err = Compact(&e.Buffer, b) } if err != nil { e.error(&MarshalerError{v.Type(), err}) } return } writeString := (*encodeState).WriteString if quoted { writeString = (*encodeState).string } switch v.Kind() { case reflect.Bool: x := v.Bool() if x { writeString(e, "true") } else { writeString(e, "false") } case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: writeString(e, strconv.Itoa64(v.Int())) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: writeString(e, strconv.Uitoa64(v.Uint())) case reflect.Float32, reflect.Float64: writeString(e, strconv.FtoaN(v.Float(), 'g', -1, v.Type().Bits())) case reflect.String: if quoted { sb, err := Marshal(v.String()) if err != nil { e.error(err) } e.string(string(sb)) } else { e.string(v.String()) } case reflect.Struct: e.WriteByte('{') t := v.Type() n := v.NumField() first := true for i := 0; i < n; i++ { f := t.Field(i) if f.PkgPath != "" { continue } tag, omitEmpty, quoted := f.Name, false, false if tv := f.Tag.Get("json"); tv != "" { if tv == "-" { continue } name, opts := parseTag(tv) if isValidTag(name) { tag = name } omitEmpty = opts.Contains("omitempty") quoted = opts.Contains("string") } fieldValue := v.Field(i) if omitEmpty && isEmptyValue(fieldValue) { continue } if first { first = false } else { e.WriteByte(',') } e.string(tag) e.WriteByte(':') e.reflectValueQuoted(fieldValue, quoted) } e.WriteByte('}') case reflect.Map: if v.Type().Key().Kind() != reflect.String { e.error(&UnsupportedTypeError{v.Type()}) } if v.IsNil() { e.WriteString("null") break } e.WriteByte('{') var sv stringValues = v.MapKeys() sort.Sort(sv) for i, k := range sv { if i > 0 { e.WriteByte(',') } e.string(k.String()) e.WriteByte(':') e.reflectValue(v.MapIndex(k)) } e.WriteByte('}') case reflect.Array, reflect.Slice: if v.Type() == byteSliceType { e.WriteByte('"') s := v.Interface().([]byte) if len(s) < 1024 { // for small buffers, using Encode directly is much faster. dst := make([]byte, base64.StdEncoding.EncodedLen(len(s))) base64.StdEncoding.Encode(dst, s) e.Write(dst) } else { // for large buffers, avoid unnecessary extra temporary // buffer space. enc := base64.NewEncoder(base64.StdEncoding, e) enc.Write(s) enc.Close() } e.WriteByte('"') break } e.WriteByte('[') n := v.Len() for i := 0; i < n; i++ { if i > 0 { e.WriteByte(',') } e.reflectValue(v.Index(i)) } e.WriteByte(']') case reflect.Interface, reflect.Ptr: if v.IsNil() { e.WriteString("null") return } e.reflectValue(v.Elem()) default: e.error(&UnsupportedTypeError{v.Type()}) } return }
func (e *encodeState) reflectValue(v reflect.Value, stringify bool) (retval interface{}) { if !v.IsValid() { e.isNull = true return } if j, ok := v.Interface().(json.Marshaler); ok { b, err := j.MarshalJSON() if err == nil { var value interface{} err = json.Unmarshal(b, &value) } if err != nil { e.error(&json.MarshalerError{v.Type(), err}) } return retval } switch v.Kind() { case reflect.Bool: if stringify { x := v.Bool() if x { e.sValue = "true" } else { e.sValue = "false" } e.isString = true retval = e.sValue } else { e.bValue = v.Bool() e.isBool = true retval = e.bValue } case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: if stringify { e.sValue = strconv.Itoa64(v.Int()) e.isString = true retval = e.sValue } else { e.iValue = v.Int() e.isInt = true retval = e.iValue } case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: if stringify { e.sValue = strconv.Uitoa64(v.Uint()) e.isString = true retval = e.sValue } else { e.uValue = v.Uint() e.isUint = true retval = e.uValue } case reflect.Float32, reflect.Float64: if stringify { e.sValue = strconv.FtoaN(v.Float(), 'g', -1, v.Type().Bits()) e.isString = true retval = e.sValue } else { e.fValue = v.Float() e.isFloat = true retval = e.fValue } case reflect.String: e.sValue = v.String() e.isString = true retval = e.sValue case reflect.Struct: t := v.Type() if t == timeType && e.timeFormat != "" { s := v.Interface().(time.Time) e.sValue = s.Format(e.timeFormat) e.isString = true retval = e.sValue break } n := v.NumField() e.obj = NewJSONObject() e.isObject = true for i := 0; i < n; i++ { f := t.Field(i) if f.PkgPath != "" { continue } tag, omitEmpty, collapse, stringify := f.Name, false, false, false if tv := f.Tag.Get("json"); tv != "" { name, opts := parseTag(tv) if isValidTag(name) { tag = name } omitEmpty = opts.Contains("omitempty") stringify = opts.Contains("string") collapse = opts.Contains("collapse") } fieldValue := v.Field(i) if omitEmpty && isEmptyValue(fieldValue) { continue } subvalue := e.newWithSameOptions().reflectValue(fieldValue, stringify) if subvalue != nil { if subobj, ok := subvalue.(JSONObject); ok { if omitEmpty && subobj.Len() == 0 { continue } if collapse { for k, v := range subobj { e.obj[k] = v } continue } } } else if omitEmpty { continue } e.obj[tag] = subvalue } retval = e.obj case reflect.Map: if v.Type().Key().Kind() != reflect.String { e.error(&json.UnsupportedTypeError{v.Type()}) } if v.IsNil() { e.isNull = true break } e.isObject = true e.obj = NewJSONObject() var sv stringValues = v.MapKeys() sort.Sort(sv) for _, k := range sv { e.obj[k.String()] = e.newWithSameOptions().reflectValue(v.MapIndex(k), false) } retval = e.obj case reflect.Array, reflect.Slice: if v.Type() == byteSliceType { s := v.Interface().([]byte) dst := make([]byte, base64.StdEncoding.EncodedLen(len(s))) base64.StdEncoding.Encode(dst, s) e.isString = true e.sValue = string(dst) break } n := v.Len() arr := make([]interface{}, n) for i := 0; i < n; i++ { arr[i] = e.newWithSameOptions().reflectValue(v.Index(i), false) } e.arr = NewJSONArrayFromArray(arr) e.isArray = true retval = e.arr case reflect.Interface, reflect.Ptr: if v.IsNil() { e.isNull = true retval = nil return } retval = e.reflectValue(v.Elem(), false) default: e.error(&json.UnsupportedTypeError{v.Type()}) } return }
// reflectValueQuoted writes the value in v to the output. // If quoted is true, the serialization is wrapped in a JSON string. func (e *encodeState) reflectValueQuoted(v reflect.Value, quoted bool) { if !v.IsValid() { e.WriteString("null") return } if j, ok := v.Interface().(Marshaler); ok && (v.Kind() != reflect.Ptr || !v.IsNil()) { b, err := j.MarshalJSON() if err == nil { // copy JSON into buffer, checking validity. err = Compact(&e.Buffer, b) } if err != nil { e.error(&MarshalerError{v.Type(), err}) } return } writeString := (*encodeState).WriteString if quoted { writeString = (*encodeState).string } switch v.Kind() { case reflect.Bool: x := v.Bool() if x { writeString(e, "true") } else { writeString(e, "false") } case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: b := strconv.Itoa64(v.Int()) if quoted { writeString(e, b) } else { e.Write([]byte(b)) } case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: b := strconv.Uitoa64(v.Uint()) if quoted { writeString(e, b) } else { e.Write([]byte(b)) } case reflect.Float32, reflect.Float64: b := strconv.FtoaN(v.Float(), 'g', -1, v.Type().Bits()) if quoted { writeString(e, b) } else { e.Write([]byte(b)) } case reflect.String: if quoted { sb, err := Marshal(v.String()) if err != nil { e.error(err) } e.string(string(sb)) } else { e.string(v.String()) } case reflect.Struct: e.WriteByte('{') first := true for _, ef := range encodeFields(v.Type()) { fieldValue := v.Field(ef.i) if ef.omitEmpty && isEmptyValue(fieldValue) { continue } if first { first = false } else { e.WriteByte(',') } e.string(ef.tag) e.WriteByte(':') e.reflectValueQuoted(fieldValue, ef.quoted) } e.WriteByte('}') case reflect.Map: if v.Type().Key().Kind() != reflect.String { e.error(&UnsupportedTypeError{v.Type()}) } if v.IsNil() { e.WriteString("null") break } e.WriteByte('{') var sv stringValues = v.MapKeys() sort.Sort(sv) for i, k := range sv { if i > 0 { e.WriteByte(',') } e.string(k.String()) e.WriteByte(':') e.reflectValue(v.MapIndex(k)) } e.WriteByte('}') case reflect.Slice: if v.IsNil() { e.WriteString("null") break } if v.Type().Elem().Kind() == reflect.Uint8 { // Byte slices get special treatment; arrays don't. s := v.Interface().([]byte) e.WriteByte('"') if len(s) < 1024 { // for small buffers, using Encode directly is much faster. dst := make([]byte, base64.StdEncoding.EncodedLen(len(s))) base64.StdEncoding.Encode(dst, s) e.Write(dst) } else { // for large buffers, avoid unnecessary extra temporary // buffer space. enc := base64.NewEncoder(base64.StdEncoding, e) enc.Write(s) enc.Close() } e.WriteByte('"') break } // Slices can be marshalled as nil, but otherwise are handled // as arrays. fallthrough case reflect.Array: e.WriteByte('[') n := v.Len() for i := 0; i < n; i++ { if i > 0 { e.WriteByte(',') } e.reflectValue(v.Index(i)) } e.WriteByte(']') case reflect.Interface, reflect.Ptr: if v.IsNil() { e.WriteString("null") return } e.reflectValue(v.Elem()) default: e.error(&UnsupportedTypeError{v.Type()}) } return }