在运行时覆盖Go JSON标签值

huangapple go评论193阅读模式
英文:

Override Go JSON tag values at runtime

问题

我在我的Web应用程序中使用"encoding/json"有以下的结构体:

  1. type CourseAssignment struct {
  2. Semester int `json:"semester" xml:"semester"`
  3. Lecture Lecture `json:"-" xml:"-"`
  4. Cos Cos `json:"-" xml:"-"`
  5. Links map[string][]Link `json:"links,omitempty" xml:"links,omitempty"`
  6. }

Lecture和Cos本身是复杂的结构体,我不希望它们被包含在我的序列化JSON中,所以我通过设置json:"-"来指示。

这个方法完美地运行。

在运行时,我如何在需要的时候覆盖这种行为,而不编写自己的序列化代码?

我的解决方案如下:

  1. func (r *CourseAssignment) Expand(depth int) CourseAssignment {
  2. if depth <= 0 {
  3. return *r
  4. }
  5. tmp := *r
  6. tmp.LectureEx = tmp.Lecture
  7. tmp.CosEx = tmp.Cos
  8. tmp.Links = nil
  9. return tmp
  10. }
  11. type CourseAssignment struct {
  12. Semester int `json:"semester" xml:"semester"`
  13. Lecture *Lecture `json:"-" xml:"-"`
  14. Cos *Cos `json:"-" xml:"-"`
  15. Links map[string][]Link `json:"links,omitempty" xml:"links,omitempty"`
  16. LectureEx *Lecture `json:"lecture,omitempty" xml:"lecture,omitempty"`
  17. CosEx *Cos `json:"course_of_study,omitempty" xml:"course_of_study,omitempty"`
  18. }

当我想要包含这些字段时,我使用Expand创建对象的副本,该副本填充了包含相同引用但在序列化中显示的字段。

英文:

I have the following struct in in my Web Application using "encoding/json"

  1. type CourseAssignment struct {
  2. Semester int `json:&quot;semester&quot; xml:&quot;semester&quot;`
  3. Lecture Lecture `json:&quot;-&quot; xml:&quot;-&quot;`
  4. Cos Cos `json:&quot;-&quot; xml:&quot;-&quot;`
  5. Links map[string][]Link `json:&quot;links,omitempty&quot; xml:&quot;links,omitempty&quot;`
  6. }

Lecture and Cos are complex structs themselves that i dont want to be included in my serialized json which i indicate by setting json:"-"

This works perfectly.

How do I override that behavior on demand during runtime, without writing my own Serialization code?

My Own Solution:

  1. func (r *CourseAssignment) Expand(depth int) CourseAssignment {
  2. if depth &lt;= 0 {
  3. return *r
  4. }
  5. tmp := *r
  6. tmp.LectureEx = tmp.Lecture
  7. tmp.CosEx = tmp.Cos
  8. tmp.Links = nil
  9. return tmp
  10. }
  11. type CourseAssignment struct {
  12. Semester int `json:&quot;semester&quot; xml:&quot;semester&quot;`
  13. Lecture *Lecture `json:&quot;-&quot; xml:&quot;-&quot;`
  14. Cos *Cos `json:&quot;-&quot; xml:&quot;-&quot;`
  15. Links map[string][]Link `json:&quot;links,omitempty&quot; xml:&quot;links,omitempty&quot;`
  16. LectureEx *Lecture `json:&quot;lecture,omitempty&quot; xml:&quot;lecture,omitempty&quot;`
  17. CosEx *Cos `json:&quot;course_of_study,omitempty&quot; xml:&quot;course_of_study,omitempty&quot;`
  18. }

When I want to include the fields, I create a Copy of the Object using Expand that fills fields that contain the same references but show up in the serialization.

答案1

得分: 4

你可以使用reflect包中的StructTag读取/获取结构体标签的值:

  1. package main
  2. import (
  3. "fmt"
  4. "reflect"
  5. )
  6. type CourseAssignment struct {
  7. Semester int `json:"semester" xml:"semester"`
  8. }
  9. func main() {
  10. ca := CourseAssignment{}
  11. st := reflect.TypeOf(ca)
  12. field := st.Field(0)
  13. fmt.Println(field.Tag.Get("json"))
  14. }

标准库中没有提供直接修改结构体标签字段的方法。

然而,有一些开源库可以实现这一功能,比如Retag

英文:

You can read/get struct tag values using StructTag from reflect package:

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;reflect&quot;
  5. )
  6. type CourseAssignment struct {
  7. Semester int `json:&quot;semester&quot; xml:&quot;semester&quot;`
  8. }
  9. func main() {
  10. ca := CourseAssignment{}
  11. st := reflect.TypeOf(ca)
  12. field := st.Field(0)
  13. fmt.Println(field.Tag.Get(&quot;json&quot;))
  14. }

There is no method to change a struct tag field in the standard library.

However, there are open-source libraries that do exactly that, like Retag.

答案2

得分: 0

在类似情况下,我通常会将这些字段设置为omitempty,然后在不希望它们包含在JSON中的情况下将其置为空:

  1. type CourseAssignment struct {
  2. Semester int `json:"semester" xml:"semester"`
  3. Lecture *Lecture `json:"lecture,omitempty" xml:"-"`
  4. Cos *Cos `json:"cos,omitempty" xml:"-"`
  5. Links map[string][]Link `json:"links,omitempty" xml:"links,omitempty"`
  6. }
  7. // 不包含Lecture/Cos进行序列化:
  8. aCourseAssignment.Lecture = nil
  9. aCourseAssignment.Cos = nil
  10. thing, err := json.Marshal(aCourseAssignment)

以上是代码的翻译部分。

英文:

What I've done in similar cases is to set these kinds of fields to omitempty, and then empty them before serializing in the cases where I don't want them included in JSON:

  1. type CourseAssignment struct {
  2. Semester int `json:&quot;semester&quot; xml:&quot;semester&quot;`
  3. Lecture *Lecture `json:&quot;lecture,omitempty&quot; xml:&quot;-&quot;`
  4. Cos *Cos `json:&quot;cos,omitempty&quot; xml:&quot;-&quot;`
  5. Links map[string][]Link `json:&quot;links,omitempty&quot; xml:&quot;links,omitempty&quot;`
  6. }
  7. // Want to serialize without including Lecture/Cos:
  8. aCourseAssignment.Lecture = nil
  9. aCourseAssignment.Cos = nil
  10. thing,err := json.Marshal(aCourseAssignment)

huangapple
  • 本文由 发表于 2017年7月11日 18:53:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/45032514.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定