blob: 839657c361a95ac34594844b35e965eaed1b3a9d [file] [log] [blame]
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package json
import (
"os"
"bytes"
"reflect"
"runtime"
"sort"
"strconv"
)
// Marshal returns the JSON encoding of v.
//
// Marshal traverses the value v recursively.
// If an encountered value implements the Marshaler interface,
// Marshal calls its MarshalJSON method to produce JSON.
//
// Otherwise, Marshal uses the following type-dependent default encodings:
//
// Boolean values encode as JSON booleans.
//
// Floating point and integer values encode as JSON numbers.
//
// String values encode as JSON strings, with each invalid UTF-8 sequence
// replaced by the encoding of the Unicode replacement character U+FFFD.
//
// Array and slice values encode as JSON arrays.
//
// Struct values encode as JSON objects. Each struct field becomes
// a member of the object. By default the object's key name is the
// struct field name converted to lower case. If the struct field
// has a tag, that tag will be used as the name instead.
//
// Map values encode as JSON objects.
// The map's key type must be string; the object keys are used directly
// as map keys.
//
// 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.
// A nil interface value encodes as the null JSON object.
//
// Channel, complex, and function values cannot be encoded in JSON.
// Attempting to encode such a value causes Marshal to return
// an InvalidTypeError.
//
// JSON cannot represent cyclic data structures and Marshal does not
// handle them. Passing cyclic structures to Marshal will result in
// an infinite recursion.
//
func Marshal(v interface{}) ([]byte, os.Error) {
e := &encodeState{}
err := e.marshal(v)
if err != nil {
return nil, err
}
return e.Bytes(), nil
}
// MarshalIndent is like Marshal but applies Indent to format the output.
func MarshalIndent(v interface{}, prefix, indent string) ([]byte, os.Error) {
b, err := Marshal(v)
if err != nil {
return nil, err
}
var buf bytes.Buffer
err = Indent(&buf, b, prefix, indent)
if err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// Marshaler is the interface implemented by objects that
// can marshal themselves into valid JSON.
type Marshaler interface {
MarshalJSON() ([]byte, os.Error)
}
type UnsupportedTypeError struct {
Type reflect.Type
}
func (e *UnsupportedTypeError) String() string {
return "json: unsupported type: " + e.Type.String()
}
type MarshalerError struct {
Type reflect.Type
Error os.Error
}
func (e *MarshalerError) String() string {
return "json: error calling MarshalJSON for type " + e.Type.String() + ": " + e.Error.String()
}
type interfaceOrPtrValue interface {
IsNil() bool
Elem() reflect.Value
}
var hex = "0123456789abcdef"
// An encodeState encodes JSON into a bytes.Buffer.
type encodeState struct {
bytes.Buffer // accumulated output
}
func (e *encodeState) marshal(v interface{}) (err os.Error) {
defer func() {
if r := recover(); r != nil {
if _, ok := r.(runtime.Error); ok {
panic(r)
}
err = r.(os.Error)
}
}()
e.reflectValue(reflect.NewValue(v))
return nil
}
func (e *encodeState) error(err os.Error) {
panic(err)
}
func (e *encodeState) reflectValue(v reflect.Value) {
if v == nil {
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 := v.(type) {
case *reflect.BoolValue:
x := v.Get()
if x {
e.WriteString("true")
} else {
e.WriteString("false")
}
case *reflect.IntValue:
e.WriteString(strconv.Itoa(v.Get()))
case *reflect.Int8Value:
e.WriteString(strconv.Itoa(int(v.Get())))
case *reflect.Int16Value:
e.WriteString(strconv.Itoa(int(v.Get())))
case *reflect.Int32Value:
e.WriteString(strconv.Itoa(int(v.Get())))
case *reflect.Int64Value:
e.WriteString(strconv.Itoa64(v.Get()))
case *reflect.UintValue:
e.WriteString(strconv.Uitoa(v.Get()))
case *reflect.Uint8Value:
e.WriteString(strconv.Uitoa(uint(v.Get())))
case *reflect.Uint16Value:
e.WriteString(strconv.Uitoa(uint(v.Get())))
case *reflect.Uint32Value:
e.WriteString(strconv.Uitoa(uint(v.Get())))
case *reflect.Uint64Value:
e.WriteString(strconv.Uitoa64(v.Get()))
case *reflect.UintptrValue:
e.WriteString(strconv.Uitoa64(uint64(v.Get())))
case *reflect.FloatValue:
e.WriteString(strconv.Ftoa(v.Get(), 'g', -1))
case *reflect.Float32Value:
e.WriteString(strconv.Ftoa32(v.Get(), 'g', -1))
case *reflect.Float64Value:
e.WriteString(strconv.Ftoa64(v.Get(), 'g', -1))
case *reflect.StringValue:
e.string(v.Get())
case *reflect.StructValue:
e.WriteByte('{')
t := v.Type().(*reflect.StructType)
n := v.NumField()
for i := 0; i < n; i++ {
if i > 0 {
e.WriteByte(',')
}
f := t.Field(i)
if f.Tag != "" {
e.string(f.Tag)
} else {
e.string(f.Name)
}
e.WriteByte(':')
e.reflectValue(v.Field(i))
}
e.WriteByte('}')
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
}
// stringValues is a slice of reflect.Value holding *reflect.StringValue.
// It implements the methods to sort by string.
type stringValues []reflect.Value
func (sv stringValues) Len() int { return len(sv) }
func (sv stringValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] }
func (sv stringValues) Less(i, j int) bool { return sv.get(i) < sv.get(j) }
func (sv stringValues) get(i int) string { return sv[i].(*reflect.StringValue).Get() }
func (e *encodeState) string(s string) {
e.WriteByte('"')
for _, c := range s {
switch {
case c < 0x20:
e.WriteString(`\u00`)
e.WriteByte(hex[c>>4])
e.WriteByte(hex[c&0xF])
case c == '\\' || c == '"':
e.WriteByte('\\')
fallthrough
default:
e.WriteRune(c)
}
}
e.WriteByte('"')
}