mirror of
https://github.com/gin-gonic/gin.git
synced 2025-12-13 13:12:17 +08:00
325 lines
8.6 KiB
Go
325 lines
8.6 KiB
Go
// Copyright 2025 Gin Core Team. All rights reserved.
|
||
// Use of this source code is governed by a MIT style
|
||
// license that can be found in the LICENSE file.
|
||
|
||
//go:build jsoniter
|
||
|
||
package json
|
||
|
||
import (
|
||
"io"
|
||
|
||
jsoniter "github.com/json-iterator/go"
|
||
)
|
||
|
||
// Package indicates what library is being used for JSON encoding.
|
||
const Package = "github.com/json-iterator/go"
|
||
|
||
func containsAF(s string) bool {
|
||
for _, char := range s {
|
||
if char >= 'a' && char <= 'f' {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
// HexStringEncoder 自定义编码器将 int64 类型编码为十六进制字符串或者把16进制转为int64
|
||
type HexStringEncoder struct {
|
||
IsInt64Pointer bool //源数据为 *int64
|
||
}
|
||
|
||
// Encode 实现 jsoniter.ValEncoder 接口
|
||
func (e *HexStringEncoder) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
|
||
if ptr == nil {
|
||
stream.WriteNil()
|
||
return
|
||
}
|
||
|
||
// Convert *int64 value to a 16-byte hexadecimal string
|
||
if e.IsInt64Pointer {
|
||
pp := (**int64)(ptr)
|
||
if *pp == nil {
|
||
stream.WriteNil()
|
||
return
|
||
}
|
||
stream.WriteString(fmt.Sprintf("%x", **pp))
|
||
return
|
||
}
|
||
|
||
// Convert int64 value to a 16-byte hexadecimal string
|
||
value := *(*int64)(ptr)
|
||
if value == 0 {
|
||
stream.WriteString("0") //0值特殊处理
|
||
} else {
|
||
stream.WriteString(fmt.Sprintf("%x", value))
|
||
}
|
||
}
|
||
|
||
func (e *HexStringEncoder) IsEmpty(ptr unsafe.Pointer) bool {
|
||
return ptr == nil || *(*int64)(ptr) == 0
|
||
}
|
||
|
||
func (codec *HexStringEncoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
|
||
valueType := iter.WhatIsNext()
|
||
if valueType == jsoniter.StringValue {
|
||
str := iter.ReadString()
|
||
var i int64
|
||
var err error
|
||
if len(str) < 17 || containsAF(str) {
|
||
i, err = strconv.ParseInt(str, 16, 64)
|
||
if err != nil {
|
||
i = 0
|
||
}
|
||
} else {
|
||
i, err = strconv.ParseInt(str, 10, 64)
|
||
if err != nil {
|
||
i = 0
|
||
}
|
||
}
|
||
|
||
*((*int64)(ptr)) = i
|
||
} else if valueType == jsoniter.NumberValue {
|
||
*((*int64)(ptr)) = iter.ReadInt64()
|
||
} else {
|
||
*((*int64)(ptr)) = 0
|
||
}
|
||
}
|
||
|
||
// EmptyObjectEncoder 实现一个编码器,当字段值为nil时,写入空对象{}
|
||
type EmptyObjectEncoder struct {
|
||
encoder jsoniter.ValEncoder
|
||
}
|
||
|
||
func (encoder *EmptyObjectEncoder) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
|
||
// If the pointer points to nil, write an empty object.
|
||
if *(*uintptr)(ptr) == 0 {
|
||
stream.WriteRaw("{}")
|
||
return
|
||
}
|
||
// Fallback to default encoding.
|
||
encoder.encoder.Encode(ptr, stream)
|
||
}
|
||
|
||
func (encoder *EmptyObjectEncoder) IsEmpty(ptr unsafe.Pointer) bool {
|
||
return encoder.encoder.IsEmpty(ptr)
|
||
}
|
||
|
||
type EmptyArrayEncoder struct {
|
||
encoder jsoniter.ValEncoder
|
||
}
|
||
|
||
func (encoder *EmptyArrayEncoder) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
|
||
// If the pointer points to nil, write an empty object.
|
||
if *(*uintptr)(ptr) == 0 {
|
||
stream.WriteRaw("[]")
|
||
return
|
||
}
|
||
// Fallback to default encoding.
|
||
encoder.encoder.Encode(ptr, stream)
|
||
}
|
||
|
||
func (encoder *EmptyArrayEncoder) IsEmpty(ptr unsafe.Pointer) bool {
|
||
return encoder.encoder.IsEmpty(ptr)
|
||
}
|
||
|
||
// 空数组64位数组
|
||
type EmptyArrayInt64Encoder struct {
|
||
encoder jsoniter.ValEncoder
|
||
decoder jsoniter.ValDecoder
|
||
}
|
||
|
||
func (encoder *EmptyArrayInt64Encoder) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
|
||
// If the pointer points to nil, write an empty object.
|
||
if *(*uintptr)(ptr) == 0 {
|
||
stream.WriteRaw("[]")
|
||
return
|
||
}
|
||
|
||
//循环数组
|
||
slice := (*[]int64)(ptr)
|
||
strSlice := make([]string, len(*slice))
|
||
for i, v := range *slice {
|
||
if v == 0 {
|
||
strSlice[i] = "0"
|
||
} else {
|
||
strSlice[i] = fmt.Sprintf("%x", v)
|
||
}
|
||
}
|
||
|
||
jsonData, err := jsonInstance.Marshal(strSlice)
|
||
if err != nil {
|
||
encoder.encoder.Encode(ptr, stream)
|
||
return
|
||
}
|
||
stream.WriteRaw(string(jsonData))
|
||
}
|
||
|
||
func (codec *EmptyArrayInt64Encoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
|
||
//str := iter.ReadString()
|
||
valueList := []int64{}
|
||
for iter.ReadArray() {
|
||
val := iter.Read()
|
||
if iter.Error != nil {
|
||
break
|
||
}
|
||
|
||
if str, ok := val.(string); ok {
|
||
//含有a-f或者正好16位使用16进制解析
|
||
if len(str) < 17 || containsAF(str) {
|
||
intVal, err := strconv.ParseInt(str, 16, 64)
|
||
if err != nil {
|
||
continue
|
||
}
|
||
valueList = append(valueList, intVal)
|
||
} else {
|
||
intVal, err := strconv.ParseInt(str, 10, 64)
|
||
if err != nil {
|
||
continue
|
||
}
|
||
valueList = append(valueList, intVal)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 将ptr解析为*[]int64类型的指针
|
||
ptrToSlice := (*[]int64)(ptr)
|
||
// 使用reflect包将ptr的内容替换为slice
|
||
reflect.ValueOf(ptrToSlice).Elem().Set(reflect.ValueOf(valueList))
|
||
}
|
||
|
||
func (encoder *EmptyArrayInt64Encoder) IsEmpty(ptr unsafe.Pointer) bool {
|
||
return encoder.encoder.IsEmpty(ptr)
|
||
}
|
||
|
||
type ToStringEncoder struct{}
|
||
|
||
func (codec *ToStringEncoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
|
||
valueType := iter.WhatIsNext()
|
||
if valueType == jsoniter.StringValue {
|
||
str := iter.ReadString()
|
||
*((*string)(ptr)) = str
|
||
} else {
|
||
valueAsString := iter.ReadAny().ToString()
|
||
*((*string)(ptr)) = valueAsString
|
||
}
|
||
}
|
||
|
||
type ToBoolEncoder struct {
|
||
decoder jsoniter.ValDecoder
|
||
DefaultVal bool
|
||
}
|
||
|
||
func (codec *ToBoolEncoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
|
||
valueType := iter.WhatIsNext()
|
||
if valueType == jsoniter.BoolValue {
|
||
codec.decoder.Decode(ptr, iter)
|
||
} else if valueType == jsoniter.NumberValue {
|
||
i := iter.ReadInt()
|
||
var myBool bool
|
||
if i > 0 {
|
||
myBool = true
|
||
} else {
|
||
myBool = false
|
||
}
|
||
*((*bool)(ptr)) = myBool
|
||
} else if valueType == jsoniter.StringValue {
|
||
str := strings.ToLower(iter.ReadString())
|
||
var myBool bool
|
||
if str == "true" || str == "1" {
|
||
myBool = true
|
||
} else if str == "false" || str == "0" || str == "-1" {
|
||
myBool = false
|
||
} else {
|
||
myBool = codec.DefaultVal
|
||
}
|
||
*((*bool)(ptr)) = myBool
|
||
} else {
|
||
str := strings.ToLower(iter.ReadAny().ToString())
|
||
var myBool bool
|
||
if str == "true" || str == "1" {
|
||
myBool = true
|
||
} else if str == "false" || str == "0" || str == "-1" {
|
||
myBool = false
|
||
} else {
|
||
myBool = codec.DefaultVal
|
||
}
|
||
*((*bool)(ptr)) = myBool
|
||
}
|
||
}
|
||
|
||
// HexStringExtension 检查 struct 字段tags,为相应的 int64 字段应用 HexStringEncoder
|
||
type ApipostExtension struct {
|
||
jsoniter.DummyExtension
|
||
}
|
||
|
||
// UpdateStructDescriptor 修改 struct 字段的编码/解码器
|
||
func (extension *ApipostExtension) UpdateStructDescriptor(structDescriptor *jsoniter.StructDescriptor) {
|
||
for _, binding := range structDescriptor.Fields {
|
||
// 检查字段类型和 tag
|
||
if binding.Field.Type().Kind() == reflect.Int64 {
|
||
//处理64位转换
|
||
if strings.Contains(binding.Field.Tag().Get("json"), "hexstring") {
|
||
binding.Encoder = &HexStringEncoder{}
|
||
binding.Decoder = &HexStringEncoder{}
|
||
}
|
||
} else if binding.Field.Type().Kind() == reflect.Ptr || binding.Field.Type().Kind() == reflect.Interface {
|
||
if strings.Contains(binding.Field.Tag().Get("json"), "hexstring") && binding.Field.Type().Type1().Elem().Kind() == reflect.Int64 { //处理*int64位转换
|
||
binding.Encoder = &HexStringEncoder{IsInt64Pointer: true}
|
||
} else if strings.Contains(binding.Field.Tag().Get("json"), "emptyobject") { //处理空对象
|
||
binding.Encoder = &EmptyObjectEncoder{binding.Encoder}
|
||
}
|
||
} else if binding.Field.Type().Kind() == reflect.Slice || binding.Field.Type().Kind() == reflect.Array {
|
||
//处理空数组
|
||
if binding.Field.Type().Type1().Elem().String() == "int64" {
|
||
//强制转64数组
|
||
int64SliceEncode := &EmptyArrayInt64Encoder{binding.Encoder, binding.Decoder}
|
||
binding.Encoder = int64SliceEncode
|
||
binding.Decoder = int64SliceEncode
|
||
} else if strings.Contains(binding.Field.Tag().Get("json"), "emptyarray") {
|
||
binding.Encoder = &EmptyArrayEncoder{binding.Encoder}
|
||
}
|
||
} else if binding.Field.Type().Kind() == reflect.String {
|
||
if strings.Contains(binding.Field.Tag().Get("json"), "tostring") {
|
||
binding.Decoder = &ToStringEncoder{}
|
||
}
|
||
} else if binding.Field.Type().Kind() == reflect.Bool {
|
||
tagStr := binding.Field.Tag().Get("json")
|
||
if strings.Contains(tagStr, "tofalse") {
|
||
binding.Decoder = &ToBoolEncoder{binding.Decoder, false}
|
||
} else if strings.Contains(tagStr, "totrue") {
|
||
binding.Decoder = &ToBoolEncoder{binding.Decoder, true}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
func init() {
|
||
json.RegisterExtension(&ApipostExtension{})
|
||
API = jsoniterApi{}
|
||
}
|
||
|
||
var json = jsoniter.ConfigCompatibleWithStandardLibrary
|
||
|
||
type jsoniterApi struct{}
|
||
|
||
func (j jsoniterApi) Marshal(v any) ([]byte, error) {
|
||
return json.Marshal(v)
|
||
}
|
||
|
||
func (j jsoniterApi) Unmarshal(data []byte, v any) error {
|
||
return json.Unmarshal(data, v)
|
||
}
|
||
|
||
func (j jsoniterApi) MarshalIndent(v any, prefix, indent string) ([]byte, error) {
|
||
return json.MarshalIndent(v, prefix, indent)
|
||
}
|
||
|
||
func (j jsoniterApi) NewEncoder(writer io.Writer) Encoder {
|
||
return json.NewEncoder(writer)
|
||
}
|
||
|
||
func (j jsoniterApi) NewDecoder(reader io.Reader) Decoder {
|
||
return json.NewDecoder(reader)
|
||
}
|