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.43k stars 1.03k forks source link

json.Get.ToVal() panic when string has null #518

Open fengxuway opened 3 years ago

fengxuway commented 3 years ago

If a json string has null element, expect a slice or struct, but json.LastError() have no error and any.ToVal() panic.

func TestJSONGet(t *testing.T) {
    var array []string
    j := json.Get([]byte(`{"data":null}`), "data")
    if j.LastError() != nil{
        t.Fatal(j.LastError())
    }
    j.ToVal(&array)
    fmt.Println(array)
}

How to fix?

Can this function return error?

err := json.Get().ToVal(pointer)
zhaozong commented 3 years ago

nilAny没有实现ToVal方法,直接继承的baseAny的ToVal https://github.com/json-iterator/go/blob/e6b9536d3649bda3e8842bb7e4fab489d79a97ea/any.go#L51-L53 为啥这里要直接panic呢,返回个error不好吗? @taowen

zhenzou commented 3 years ago

先判断是不是为null:j.ValueType() == jsoniter.NilValue 要使用一个 any 的value,预期就是应该先判断是否是 nil。panic 可以提前暴露错误

amanbolat commented 3 years ago

I have encountered the same problem. There is my solution:

val := jsoniter.Get(b, "some_field")
err := val.LastError()
if err != nil {
    return fmt.Errorf("failed to unmarshal, %s", err)
}
fmt.Println("size", val.Size())
if val.Size() == 0 {
    return fmt.Errorf("failed to unmarshal")
}

I found that baseAnys size is always equal to zero:

func (any *baseAny) Size() int {
    return 0
}