【问题标题】:Changing JSON tags in struct with custom MarshalJSON使用自定义 MarshalJSON 更改结构中的 JSON 标记
【发布时间】:2018-06-07 19:31:51
【问题描述】:

我们得到一些 JSON 输入,解组,执行一些工作,然后编组并发送到其他地方。我们得到的 JSON 可能有一个名为“user”的字段。当我们编组回 JSON 时,我们需要将该字段“用户”更改为“用户名”。我们可以通过创建一个具有所有相同字段但不同 JSON 标签的新结构来做到这一点,但这似乎有点麻烦。我以为自定义编组器会在这里工作,但我有点卡住了。考虑以下代码。

package main

import (
    "encoding/json"
    "fmt"
)

type StructA struct {
    Username string `json:"user"`
    Process  string `json:"process"`
}

func main() {

    var test1 StructA
    err := json.Unmarshal([]byte(`{"user": "user123", "process": "something"}`), &test1)
    if err != nil {
        fmt.Println(err)
    }

    // do some work with test1

    jsonByte, err := json.Marshal(&test1)
    if err != nil {
        fmt.Println(err)
    }

    fmt.Println(string(jsonByte))

}

func (u *StructA) MarshalJSON() ([]byte, error) {
    type Alias StructA
    return json.Marshal(&struct {
        Username string `json:"username"`
        *Alias
    }{
        Username: u.Username,
        Alias:    (*Alias)(u),
    })
}

https://play.golang.org/p/_w0rlQrcgrW

理想情况下,这将允许我将该字段上的 JSON 标记从“用户”更改为“用户名”。但是,我得到了“用户名”和“用户”。

{"username":"user123","user":"user123","process":"something"}

我当然可以创建一个全新的结构,用我想要的标签来镜像 StructA,但我不必复制每个字段并担心保持这两个结构同步。这不是世界末日,但似乎不是一个好方法。

明确地说,我正在寻找的最终结果如下:

{"username":"user123","process":"something"}

我确定我在这里遗漏了一些琐碎的事情,但这是漫长的一周,我们将不胜感激。谢谢!

【问题讨论】:

  • 你得到的结果是因为你在创建一个新的编组时嵌入了结构。你已经嵌入了整个StructA

标签: json go


【解决方案1】:

一种选择可能是让一个结构具有不变的值,而不是两个替代结构,它们都包括该结构并且只有变化的值。然后,您使用一个用于解组,第二个用于编组。

type StructA struct {
    Process  string `json:"process"`
    ...
}

type WithUser struct {
    StructA
    Username `json:"user"`
}

type WithUsername struct {
    StructA
    Username `json:"username"`
}

这将需要多个结构,但每个结构都不能重复,并且可以非常灵活地包含在内,而不是将要更改的内容硬编码为自定义封送函数。

【讨论】:

    【解决方案2】:

    使用反射创建结构并更改其标签

    package main
    
    import (
        "encoding/json"
        "fmt"
        "reflect"
    )
    
    type StructA struct {
        Username string `json:"user"`
        Process  string `json:"process"`
    }
    
    func main() {
    
        var test1 StructA
        err := json.Unmarshal([]byte(`{"user": "user123", "process": "something"}`), &test1)
        if err != nil {
            fmt.Println(err)
        }
    
        // do some work with test1
    
        jsonByte, err := json.Marshal(&test1)
        if err != nil {
            fmt.Println(err)
        }
    
        fmt.Println(string(jsonByte))
    
    }
    
    func (u *StructA) MarshalJSON() ([]byte, error) {
        // get old struct fields
        uType := reflect.TypeOf(u).Elem()
        userNameField, _ := uType.FieldByName("Username")
        // set username field tag
        userNameField.Tag = `json:"username"`
        processField, _ := uType.FieldByName("Process")
        newType := reflect.StructOf([]reflect.StructField{userNameField, processField})
        // set new value field
        oldValue := reflect.ValueOf(u).Elem()
        newtValue := reflect.New(newType).Elem()
        for i := 0; i < oldValue.NumField(); i++ {
            newtValue.Field(i).Set(oldValue.Field(i))
        }
        return json.Marshal(newtValue.Interface())
    }
    

    【讨论】:

      猜你喜欢
      • 2023-03-09
      • 1970-01-01
      • 1970-01-01
      • 2021-10-16
      • 1970-01-01
      • 2020-04-15
      • 2020-06-13
      • 2015-08-01
      • 1970-01-01
      相关资源
      最近更新 更多