首页 > 解决方案 > 将 json null 解组为 NullString 的指针

问题描述

我无法将json.Unmarshal空值放入*NullString结构内的字段中。这是我的意思的简化示例:

package main

import (
  "database/sql"
  "encoding/json"
  "log"
)

// NullString
type NullString struct {
  sql.NullString
}

func (n *NullString) UnmarshalJSON(b []byte) error {

  n.Valid = string(b) != "null"
  e := json.Unmarshal(b, &n.String)
  return e
}

type Person struct {
  Name *NullString `json:"name"`
}

func BuildUpdateSQL(jsonString string) string {

  p := Person{}
  e := json.Unmarshal([]byte(jsonString),&p)
  if e != nil {
    log.Println(e)
  }

  if p.Name != nil {
    log.Println(p,p.Name)
  } else {
    log.Println(p)
  }
  return ""
}
func main() {
  // Correctly leaves p.Name unset
  BuildUpdateSQL(`{"field_not_exist":"samantha"}`)

  // Correctly sets p.Name
  BuildUpdateSQL(`{"name":"samantha"}`)

  // Incorrectly leaves p.Name as nil when I really want p.Name to have a NullString with .Valid == false
  BuildUpdateSQL(`{"name":null}`)
}

如您所见,解编组适用于非空 json 值。但是当我传入一个 null json 值时, NullString 解组器似乎甚至没有触发。

有人知道我在做什么错吗?

背景

我尝试这样做的原因是因为我计划从 REST API 获取 JSON 值。并非 API 中的所有字段都是必填字段。因此,我使用结构字段的指针来帮助我构建 SQL 更新语句,因为:

标签: jsongounmarshalling

解决方案


是的,这是因为以下解组规则:

要将 JSON 解组为指针,Unmarshal 首先处理 JSON 为 JSON 文字 null 的情况。在这种情况下,Unmarshal 将指针设置为 nil。否则,Unmarshal 将 JSON 解组为指针指向的值。

文档encoding/json)。

我建议做的是添加一个Set在触发 UnmarshalJSON 时更改为 true 的字段(如果有任何值,保证会被触发),然后将其更改*NullString为 simple NullString,如下所示:

package main

import (
    "database/sql"
    "encoding/json"
    "log"
)

// NullString
type NullString struct {
    Set bool
    sql.NullString
}

func (n *NullString) UnmarshalJSON(b []byte) error {
    n.Set = true
    n.Valid = string(b) != "null"
    e := json.Unmarshal(b, &n.String)
    return e
}

type Person struct {
    Name NullString `json:"name"`
}

func BuildUpdateSQL(jsonString string) string {
    p := Person{}
    e := json.Unmarshal([]byte(jsonString), &p)
    if e != nil {
        log.Println(e)
    }

    log.Printf("%#v", p)
    return ""
}

func main() {
    BuildUpdateSQL(`{"field_not_exist":"samantha"}`)
    BuildUpdateSQL(`{"name":"samantha"}`)
    BuildUpdateSQL(`{"name":null}`)
}

操场


推荐阅读