英文:
Custom Unmarshal Tags in Golang from Custom Mapping
问题
我正在尝试根据数据库中指定的自定义映射来取消映射一个结构体,该映射指定了哪些 JSON 标签对应哪些结构体字段。
我有一个基本的工作解决方案,大致如下:
package main
import (
"encoding/json"
"errors"
"fmt"
"log"
)
type Mapping struct {
ObjColumnName string
JSONColumnName string
}
type Obj struct {
Name string
Age float64
m []Mapping
}
func (o *Obj) UnmarshalJSON(data []byte) error {
var a map[string]interface{}
json.Unmarshal(data, &a)
for _, mapping := range o.m {
switch mapping.ObjColumnName {
case "Name":
o.Name = a[mapping.JSONColumnName].(string)
case "Age":
o.Age = a[mapping.JSONColumnName].(float64)
default:
return errors.New("Unknown mapping")
}
}
return nil
}
func main() {
o := Obj{
m: []Mapping{
{
ObjColumnName: "Name",
JSONColumnName: "first_name_last_name",
},
{
ObjColumnName: "Age",
JSONColumnName: "years_since_birth",
},
},
}
blob := `{"first_name_last_name": "Jason Bourne", "years_since_birth": 15}`
if err := json.Unmarshal([]byte(blob), &o); err != nil {
log.Fatal(err)
}
fmt.Printf("Custom Unmapped: %+v", o)
// Custom Unmapped: {Name:Jason Bourne Age:15 m:[{ObjColumnName:Name JSONColumnName:first_name_last_name} {ObjColumnName:Age JSONColumnName:years_since_birth}]}
}
所以你可以看到,我们成功地改变了映射到 Name
和 Age
的内容。
然而,我不喜欢这种实现的原因是:
- 我基本上需要在这里重新定义对象类型:
case "Name":
o.Name = a[mapping.JSONColumnName].(string)
case "Age":
o.Age = a[mapping.JSONColumnName].(float64)
- 我认为将映射附加到
Obj
(Obj.m
) 有点笨拙。
有没有更好的方法在解组时动态设置 JSON 标签,这样我就不必做这种笨拙的事情了?
英文:
I'm trying to unmap a struct based on a custom mapping in my DB that specifies which json tags correspond to which struct fields.
I have a basic working solution that looks somewhat like this:
package main
import (
"encoding/json"
"errors"
"fmt"
"log"
)
type Mapping struct {
ObjColumnName string
JSONColumnName string
}
type Obj struct {
Name string
Age float64
m []Mapping
}
func (o *Obj) UnmarshalJSON(data []byte) error {
var a map[string]interface{}
json.Unmarshal(data, &a)
for _, mapping := range o.m {
switch mapping.ObjColumnName {
case "Name":
o.Name = a[mapping.JSONColumnName].(string)
case "Age":
o.Age = a[mapping.JSONColumnName].(float64)
default:
return errors.New("Unknown mapping")
}
}
return nil
}
func main() {
o := Obj{
m: []Mapping{
{
ObjColumnName: "Name",
JSONColumnName: "first_name_last_name",
},
{
ObjColumnName: "Age",
JSONColumnName: "years_since_birth",
},
},
}
blob := `{"first_name_last_name": "Jason Bourne", "years_since_birth": 15}`
if err := json.Unmarshal([]byte(blob), &o); err != nil {
log.Fatal(err)
}
fmt.Printf("Custom Unmapped: %+v", o)
// Custom Unmapped: {Name:Jason Bourne Age:15 m:[{ObjColumnName:Name JSONColumnName:first_name_last_name} {ObjColumnName:Age JSONColumnName:years_since_birth}]}
}
so you can see here that we can successfully change what maps to Name
and what maps to Age
.
However what I don't like about this implementation is:
- I have to basically redefine the object types here:
case "Name":
o.Name = a[mapping.JSONColumnName].(string)
case "Age":
o.Age = a[mapping.JSONColumnName].(float64)
- I think attaching the mappings to
Obj
(Obj.m
) is a little hacky
Is there a better way to dynamically set the json tags when Unmarshalling so that I don't have to do hacky stuff like this?
答案1
得分: 1
哇,我被局限在认为我必须做一些花哨的反射中。你可以简单地重新映射键,然后不进行任何花哨的解组:https://go.dev/play/p/kSJbSAcVLm6
不过,从性能的角度来看,这并不理想。如果有人能回答如何在不进行两次解组的情况下完成它,那就太好了!
英文:
Wow, was pigeon-holed into thinking I have to do some fancy reflection. You can just remap the keys and then not do any fancy unmarshalling: https://go.dev/play/p/kSJbSAcVLm6
This isn't ideal from a performance perspective though. If someone could answer how to do it without doing 2 Unmarshall's that would be great!
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论