Поле JSON установлено на ноль против поля, которого нет

Есть ли способ, в golang, увидеть, могу ли я отличить поле json от значения null от поля json, не находящегося там, когда он не привязан к структуре? Потому что оба устанавливают значение в struct равным nil, но мне нужно знать, было ли это поле для начала, и чтобы убедиться, что кто-то установил его в null.

{
  "somefield1":"somevalue1",
  "somefield2":null
}

VS

{
  "somefield1":"somevalue1",
}

Оба jsons будут равны нулю, если они не будут объединены в структуру. Любые полезные ресурсы будут очень благодарны!

Ответ 1

Используйте json.RawMessage чтобы "задержать" процесс json.RawMessage чтобы определить необработанный байт, прежде чем принять решение:

var data = []byte('{
        "somefield1":"somevalue1",
        "somefield2": null
}')

type Data struct {
    SomeField1 string          
    SomeField2 json.RawMessage
}

func main() {
    d := &Data{}

    _ = json.Unmarshal(data, &d)

    fmt.Println(d.SomeField1)

    if len(d.SomeField2) > 0 {
        if string(d.SomeField2) == "null" {
            fmt.Println("somefield2 is there but null")
        } else {
            fmt.Println("somefield2 is there and not null")
            // Do something with the data
        }
    } else {
        fmt.Println("somefield2 doesn't exist")
    }
}

Смотрите игровую площадку https://play.golang.org/p/Wganpf4sbO

Ответ 2

Если вы размонтируете объект в интерфейсе карты [string] {}, вы можете просто проверить, есть ли там поле

type unMarshalledObject map[string]interface{}
json.Unmarshall(input, unMarshhaledObject)
_, ok := unMarshalledObject["somefield2"]

Перейти на площадку

Ответ 3

Хороший вопрос.

Я считаю, что вы можете использовать https://golang.org/pkg/encoding/json/#RawMessage как:

type MyMessage struct {
  somefield1 string
  somefield2 json.RawMessage
}

Итак, после unmarshalling вы должны иметь []byte("null") в случае null и nil, если они отсутствуют.

Вот код детской площадки: https://play.golang.org/p/UW8L68K068

Ответ 4

Если поле struct является указателем, JSON-декодер будет выделять новую переменную, если это поле присутствует или оставить его нулевым, если нет. Поэтому я предлагаю использовать указатели.

type Data struct {
    StrField *string
    IntField *int
}
...
if data.StrField != nil {
    handle(*data.StrField)
}

Ответ 5

Используя github.com/golang/protobuf/ptypes/struct и jsonpb github.com/golang/protobuf/jsonpb, вы можете сделать следующее:

func TestFunTest(t *testing.T) {
    p := &pb.KnownTypes{}
    e := UnmarshalString(`{"val":null}`, p)
    fmt.Println(e, p)
    p = &pb.KnownTypes{}
    e = UnmarshalString(`{"val":1}`, p)
    fmt.Println(e, p)
    p = &pb.KnownTypes{}
    e = UnmarshalString(`{"val":"string"}`, p)
    fmt.Println(e, p)
    p = &pb.KnownTypes{}
    e = UnmarshalString(`{}`, p)
    fmt.Println(e, p)
}

Вывод:

[ `go test -test.run="^TestFunTest$"` | done: 1.275431416s ]
    <nil> val:<null_value:NULL_VALUE > 
    <nil> val:<number_value:1 > 
    <nil> val:<string_value:"string" > 
    <nil> 
    PASS