func (cdc *Codec) encodeReflectJSON(w io.Writer, info *TypeInfo, rv reflect.Value, fopts FieldOptions) (err error) {
	if !rv.IsValid() {
		panic("should not happen")
	}
	if printLog {
		spew.Printf("(E) encodeReflectJSON(info: %v, rv: %#v (%v), fopts: %v)\n",
			info, rv.Interface(), rv.Type(), fopts)
		defer func() {
			fmt.Printf("(E) -> err: %v\n", err)
		}()
	}

	// Dereference value if pointer.
	var isNilPtr bool
	rv, _, isNilPtr = derefPointers(rv)

	// Write null if necessary.
	if isNilPtr {
		err = writeStr(w, `null`)
		return
	}

	// Special case:
	if rv.Type() == timeType {
		// Amino time strips the timezone.
		// NOTE: This must be done before json.Marshaler override below.
		ct := rv.Interface().(time.Time).Round(0).UTC()
		rv = reflect.ValueOf(ct)
	}
	// Handle override if rv implements json.Marshaler.
	if rv.CanAddr() { // Try pointer first.
		if rv.Addr().Type().Implements(jsonMarshalerType) {
			err = invokeMarshalJSON(w, rv.Addr())
			return
		}
	} else if rv.Type().Implements(jsonMarshalerType) {
		err = invokeMarshalJSON(w, rv)
		return
	}

	// Handle override if rv implements json.Marshaler.
	if info.IsAminoMarshaler {
		// First, encode rv into repr instance.
		var rrv, rinfo = reflect.Value{}, (*TypeInfo)(nil)
		rrv, err = toReprObject(rv)
		if err != nil {
			return
		}
		rinfo, err = cdc.getTypeInfo_wlock(info.AminoMarshalReprType)
		if err != nil {
			return
		}
		// Then, encode the repr instance.
		err = cdc.encodeReflectJSON(w, rinfo, rrv, fopts)
		return
	}

	switch info.Type.Kind() {

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

	case reflect.Interface:
		return cdc.encodeReflectJSONInterface(w, info, rv, fopts)

	case reflect.Array, reflect.Slice:
		return cdc.encodeReflectJSONList(w, info, rv, fopts)

	case reflect.Struct:
		return cdc.encodeReflectJSONStruct(w, info, rv, fopts)

	case reflect.Map:
		return cdc.encodeReflectJSONMap(w, info, rv, fopts)

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

	case reflect.Int64, reflect.Int:
		_, err = fmt.Fprintf(w, `"%d"`, rv.Int()) // JS can't handle int64
		return

	case reflect.Uint64, reflect.Uint:
		_, err = fmt.Fprintf(w, `"%d"`, rv.Uint()) // JS can't handle uint64
		return

	case reflect.Int32, reflect.Int16, reflect.Int8,
		reflect.Uint32, reflect.Uint16, reflect.Uint8:
		return invokeStdlibJSONMarshal(w, rv.Interface())

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

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

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

	default:
		panic(fmt.Sprintf("unsupported type %v", info.Type.Kind()))
	}
}
func (cdc *Codec) encodeReflectJSON(w io.Writer, info *TypeInfo, rv reflect.Value, fopts FieldOptions) (err error) {
	if !rv.IsValid() {
		panic("should not happen")
	}
	if printLog {
		spew.Printf("(E) encodeReflectJSON(info: %v, rv: %#v (%v), fopts: %v)\n",
			info, rv.Interface(), rv.Type(), fopts)
		defer func() {
			fmt.Printf("(E) -> err: %v\n", err)
		}()
	}

	// Dereference value if pointer.
	var isNilPtr bool
	rv, _, isNilPtr = derefPointers(rv)

	// Write null if necessary.
	if isNilPtr {
		err = writeStr(w, `null`)
		return
	}

	// Special case:
	if rv.Type() == timeType {
		// Amino time strips the timezone.
		// NOTE: This must be done before json.Marshaler override below.
		ct := rv.Interface().(time.Time).Round(0).UTC()
		rv = reflect.ValueOf(ct)
	}
	// Handle override if rv implements json.Marshaler.
	if rv.CanAddr() { // Try pointer first.
		if rv.Addr().Type().Implements(jsonMarshalerType) {
			err = invokeMarshalJSON(w, rv.Addr())
			return
		}
	} else if rv.Type().Implements(jsonMarshalerType) {
		err = invokeMarshalJSON(w, rv)
		return
	}

	// Handle override if rv implements json.Marshaler.
	if info.IsAminoMarshaler {
		// First, encode rv into repr instance.
		var rrv, rinfo = reflect.Value{}, (*TypeInfo)(nil)
		rrv, err = toReprObject(rv)
		if err != nil {
			return
		}
		rinfo, err = cdc.getTypeInfo_wlock(info.AminoMarshalReprType)
		if err != nil {
			return
		}
		// Then, encode the repr instance.
		err = cdc.encodeReflectJSON(w, rinfo, rrv, fopts)
		return
	}

	switch info.Type.Kind() {

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

	case reflect.Interface:
		return cdc.encodeReflectJSONInterface(w, info, rv, fopts)

	case reflect.Array, reflect.Slice:
		return cdc.encodeReflectJSONList(w, info, rv, fopts)

	case reflect.Struct:
		return cdc.encodeReflectJSONStruct(w, info, rv, fopts)

	case reflect.Map:
		return cdc.encodeReflectJSONMap(w, info, rv, fopts)

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

	case reflect.Int64, reflect.Int:
		_, err = fmt.Fprintf(w, `"%d"`, rv.Int()) // JS can't handle int64
		return

	case reflect.Uint64, reflect.Uint:
		_, err = fmt.Fprintf(w, `"%d"`, rv.Uint()) // JS can't handle uint64
		return

	case reflect.Int32, reflect.Int16, reflect.Int8,
		reflect.Uint32, reflect.Uint16, reflect.Uint8:
		return invokeStdlibJSONMarshal(w, rv.Interface())

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

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

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

	default:
		panic(fmt.Sprintf("unsupported type %v", info.Type.Kind()))
	}
}
//----------------------------------------
// cdc.encodeReflectJSON
// This is the main entrypoint for encoding all types in json form.  This
// function calls encodeReflectJSON*, and generally those functions should
// only call this one, for the disfix wrapper is only written here.
// NOTE: Unlike encodeReflectBinary, rv may be a pointer.
// CONTRACT: rv is valid.