json-iterator / go

A high-performance 100% compatible drop-in replacement of "encoding/json"
http://jsoniter.com/migrate-from-go-std.html
MIT License
13.42k stars 1.03k forks source link

多个不同库的 RegisterTypeDecoderFunc 会覆盖? #622

Open hiscaler opened 2 years ago

hiscaler commented 2 years ago

我用了 A 库 和 B 库,两者都设置了 RegisterTypeDecoderFunc,比如

// A 库
jsoniter.RegisterTypeDecoderFunc("bool", func(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
        switch iter.WhatIsNext() {
        case jsoniter.StringValue:
            var t bool
            v := strings.TrimSpace(iter.ReadString())
            if v != "" {
                var err error
                if t, err = strconv.ParseBool(strings.ToLower(v)); err != nil {
                    iter.Error = err
                    return
                }
            }
            *((*bool)(ptr)) = t
        case jsoniter.NumberValue:
            if v, err := iter.ReadNumber().Int64(); err != nil {
                iter.Error = err
                return
            } else {
                *((*bool)(ptr)) = v > 0
            }
        case jsoniter.NilValue:
            iter.Skip()
            *((*bool)(ptr)) = false
        default:
            *((*bool)(ptr)) = iter.ReadBool()
        }
    })
// B 库
jsoniter.RegisterTypeDecoderFunc("bool", func(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
        switch iter.WhatIsNext() {
        case jsoniter.StringValue:
            var t bool
            v := strings.TrimSpace(iter.ReadString())
            if v != "" {
                var err error
                if t, err = strconv.ParseBool(strings.ToLower(v)); err != nil {
                    iter.Error = err
                    return
                }
            }
            *((*bool)(ptr)) = t
        case jsoniter.NumberValue:
            if v, err := iter.ReadNumber().Int64(); err != nil {
                iter.Error = err
                return
            } else {
                *((*bool)(ptr)) = v == 0
            }
        case jsoniter.NilValue:
            iter.Skip()
            *((*bool)(ptr)) = false
        default:
            *((*bool)(ptr)) = iter.ReadBool()
        }
    })

简单的说就是 A 库 1 看做是 True,而 B 库 0 看做是 True,如果同一个方法中同时使用了两个库,则会导致混乱。请问有什么办法避免吗?

mjscjj commented 2 years ago

same problem

mjscjj commented 2 years ago

请问你是怎么解决的?

hiscaler commented 2 years ago

@mjscjj 没找到办法,所以没处理了

iyaozhen commented 2 years ago

相同的问题,json-iterator 怎么能new一个局部实例然后再RegisterTypeDecoderFunc使用呢,这样就不影响他人了

iyaozhen commented 2 years ago

@hiscaler @mjscjj 我解决了,使用 RegisterExtension 还有一个点就是需要重新定义一个config,这样只这个config生效

type customNumberExtension struct {
    jsoniter.DummyExtension
}

func (cne *customNumberExtension) CreateDecoder(typ reflect2.Type) jsoniter.ValDecoder {
    if typ.String() == "interface {}" {
        return &numberValDecoder{}
    }
    return nil
}

type numberValDecoder struct{}

func (n *numberValDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
    switch iter.WhatIsNext() {
    case jsoniter.NumberValue:
        var number any
        // 省略具体的业务逻辑
        *(*interface{})(ptr) = number
    default:
        *(*interface{})(ptr) = iter.Read()
    }
}

var newConfig = jsoniter.Config{
    EscapeHTML: true,
}.Froze()

func init() {
    newConfig.RegisterExtension(&customNumberExtension{})
}

func JsonDecodeUseNumber(data []byte, v interface{}) error {
    return newConfig.Unmarshal(data, v)
}
hiscaler commented 2 years ago

@iyaozhen 牛!得空我测试一下看看,谢谢你!