json-decode.go
func (cdc *Codec) decodeReflectJSON(bz []byte, info *TypeInfo, rv reflect.Value, fopts FieldOptions) (err error) {
	if !rv.CanAddr() {
		panic("rv not addressable")
	}
	if info.Type.Kind() == reflect.Interface && rv.Kind() == reflect.Ptr {
		panic("should not happen")
	}
	if printLog {
		spew.Printf("(D) decodeReflectJSON(bz: %s, info: %v, rv: %#v (%v), fopts: %v)\n",
			bz, info, rv.Interface(), rv.Type(), fopts)
		defer func() {
			fmt.Printf("(D) -> err: %v\n", err)
		}()
	}

	// Special case for null for either interface, pointer, slice
	// NOTE: This doesn't match the binary implementation completely.
	if nullBytes(bz) {
		rv.Set(reflect.Zero(rv.Type()))
		return
	}

	// Dereference-and-construct pointers all the way.
	// This works for pointer-pointers.
	for rv.Kind() == reflect.Ptr {
		if rv.IsNil() {
			newPtr := reflect.New(rv.Type().Elem())
			rv.Set(newPtr)
		}
		rv = rv.Elem()
	}

	// Special case:
	if rv.Type() == timeType {
		// Amino time strips the timezone, so must end with Z.
		if len(bz) >= 2 && bz[0] == '"' && bz[len(bz)-1] == '"' {
			if bz[len(bz)-2] != 'Z' {
				err = fmt.Errorf("Amino:JSON time must be UTC and end with 'Z' but got %s.", bz)
				return
			}
		} else {
			err = fmt.Errorf("Amino:JSON time must be an RFC3339Nano string, but got %s.", bz)
			return
		}
	}

	// Handle override if a pointer to rv implements json.Unmarshaler.
	if rv.Addr().Type().Implements(jsonUnmarshalerType) {
		err = rv.Addr().Interface().(json.Unmarshaler).UnmarshalJSON(bz)
		return
	}

	// Handle override if a pointer to rv implements UnmarshalAmino.
	if info.IsAminoUnmarshaler {
		// First, decode repr instance from bytes.
		rrv, rinfo := reflect.New(info.AminoUnmarshalReprType).Elem(), (*TypeInfo)(nil)
		rinfo, err = cdc.getTypeInfo_wlock(info.AminoUnmarshalReprType)
		if err != nil {
			return
		}
		err = cdc.decodeReflectJSON(bz, rinfo, rrv, fopts)
		if err != nil {
			return
		}
		// Then, decode from repr instance.
		uwrm := rv.Addr().MethodByName("UnmarshalAmino")
		uwouts := uwrm.Call([]reflect.Value{rrv})
		erri := uwouts[0].Interface()
		if erri != nil {
			err = erri.(error)
		}
		return
	}

	switch ikind := info.Type.Kind(); ikind {

	//----------------------------------------
	// Complex

	case reflect.Interface:
		err = cdc.decodeReflectJSONInterface(bz, info, rv, fopts)

	case reflect.Array:
		err = cdc.decodeReflectJSONArray(bz, info, rv, fopts)

	case reflect.Slice:
		err = cdc.decodeReflectJSONSlice(bz, info, rv, fopts)

	case reflect.Struct:
		err = cdc.decodeReflectJSONStruct(bz, info, rv, fopts)

	case reflect.Map:
		err = cdc.decodeReflectJSONMap(bz, info, rv, fopts)

	//----------------------------------------
	// Signed, Unsigned

	case reflect.Int64, reflect.Int:
		fallthrough
	case reflect.Uint64, reflect.Uint:
		if bz[0] != '"' || bz[len(bz)-1] != '"' {
			err = fmt.Errorf("invalid character -- Amino:JSON int/int64/uint/uint64 expects quoted values for javascript numeric support, got: %v.", string(bz))
			if err != nil {
				return
			}
		}
		bz = bz[1 : len(bz)-1]
		fallthrough
	case reflect.Int32, reflect.Int16, reflect.Int8,
		reflect.Uint32, reflect.Uint16, reflect.Uint8:
		err = invokeStdlibJSONUnmarshal(bz, rv, fopts)

	//----------------------------------------
	// Misc

	case reflect.Float32, reflect.Float64:
		if !fopts.Unsafe {
			return errors.New("Amino:JSON float* support requires `amino:\"unsafe\"`.")
		}
		fallthrough
	case reflect.Bool, reflect.String:
		err = invokeStdlibJSONUnmarshal(bz, rv, fopts)

	//----------------------------------------
	// Default

	default:
		panic(fmt.Sprintf("unsupported type %v", info.Type.Kind()))
	}

	return
}
func (cdc *Codec) decodeReflectJSON(bz []byte, info *TypeInfo, rv reflect.Value, fopts FieldOptions) (err error) {
	if !rv.CanAddr() {
		panic("rv not addressable")
	}
	if info.Type.Kind() == reflect.Interface && rv.Kind() == reflect.Ptr {
		panic("should not happen")
	}
	if printLog {
		spew.Printf("(D) decodeReflectJSON(bz: %s, info: %v, rv: %#v (%v), fopts: %v)\n",
			bz, info, rv.Interface(), rv.Type(), fopts)
		defer func() {
			fmt.Printf("(D) -> err: %v\n", err)
		}()
	}

	// Special case for null for either interface, pointer, slice
	// NOTE: This doesn't match the binary implementation completely.
	if nullBytes(bz) {
		rv.Set(reflect.Zero(rv.Type()))
		return
	}

	// Dereference-and-construct pointers all the way.
	// This works for pointer-pointers.
	for rv.Kind() == reflect.Ptr {
		if rv.IsNil() {
			newPtr := reflect.New(rv.Type().Elem())
			rv.Set(newPtr)
		}
		rv = rv.Elem()
	}

	// Special case:
	if rv.Type() == timeType {
		// Amino time strips the timezone, so must end with Z.
		if len(bz) >= 2 && bz[0] == '"' && bz[len(bz)-1] == '"' {
			if bz[len(bz)-2] != 'Z' {
				err = fmt.Errorf("Amino:JSON time must be UTC and end with 'Z' but got %s.", bz)
				return
			}
		} else {
			err = fmt.Errorf("Amino:JSON time must be an RFC3339Nano string, but got %s.", bz)
			return
		}
	}

	// Handle override if a pointer to rv implements json.Unmarshaler.
	if rv.Addr().Type().Implements(jsonUnmarshalerType) {
		err = rv.Addr().Interface().(json.Unmarshaler).UnmarshalJSON(bz)
		return
	}

	// Handle override if a pointer to rv implements UnmarshalAmino.
	if info.IsAminoUnmarshaler {
		// First, decode repr instance from bytes.
		rrv, rinfo := reflect.New(info.AminoUnmarshalReprType).Elem(), (*TypeInfo)(nil)
		rinfo, err = cdc.getTypeInfo_wlock(info.AminoUnmarshalReprType)
		if err != nil {
			return
		}
		err = cdc.decodeReflectJSON(bz, rinfo, rrv, fopts)
		if err != nil {
			return
		}
		// Then, decode from repr instance.
		uwrm := rv.Addr().MethodByName("UnmarshalAmino")
		uwouts := uwrm.Call([]reflect.Value{rrv})
		erri := uwouts[0].Interface()
		if erri != nil {
			err = erri.(error)
		}
		return
	}

	switch ikind := info.Type.Kind(); ikind {

	//----------------------------------------
	// Complex

	case reflect.Interface:
		err = cdc.decodeReflectJSONInterface(bz, info, rv, fopts)

	case reflect.Array:
		err = cdc.decodeReflectJSONArray(bz, info, rv, fopts)

	case reflect.Slice:
		err = cdc.decodeReflectJSONSlice(bz, info, rv, fopts)

	case reflect.Struct:
		err = cdc.decodeReflectJSONStruct(bz, info, rv, fopts)

	case reflect.Map:
		err = cdc.decodeReflectJSONMap(bz, info, rv, fopts)

	//----------------------------------------
	// Signed, Unsigned

	case reflect.Int64, reflect.Int:
		fallthrough
	case reflect.Uint64, reflect.Uint:
		if bz[0] != '"' || bz[len(bz)-1] != '"' {
			err = fmt.Errorf("invalid character -- Amino:JSON int/int64/uint/uint64 expects quoted values for javascript numeric support, got: %v.", string(bz))
			if err != nil {
				return
			}
		}
		bz = bz[1 : len(bz)-1]
		fallthrough
	case reflect.Int32, reflect.Int16, reflect.Int8,
		reflect.Uint32, reflect.Uint16, reflect.Uint8:
		err = invokeStdlibJSONUnmarshal(bz, rv, fopts)

	//----------------------------------------
	// Misc

	case reflect.Float32, reflect.Float64:
		if !fopts.Unsafe {
			return errors.New("Amino:JSON float* support requires `amino:\"unsafe\"`.")
		}
		fallthrough
	case reflect.Bool, reflect.String:
		err = invokeStdlibJSONUnmarshal(bz, rv, fopts)

	//----------------------------------------
	// Default

	default:
		panic(fmt.Sprintf("unsupported type %v", info.Type.Kind()))
	}

	return
}
//----------------------------------------
// cdc.decodeReflectJSON
// CONTRACT: rv.CanAddr() is true.