Пример #1
0
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
}
Пример #2
0
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
}
Пример #3
0
// 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
}
Пример #4
0
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
}
Пример #5
0
// 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
}