在Golang中自定义映射的情况下,使用自定义的Unmarshal标签。

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

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}]}
}

所以你可以看到,我们成功地改变了映射到 NameAge 的内容。

然而,我不喜欢这种实现的原因是:

  1. 我基本上需要在这里重新定义对象类型:
        case "Name":
            o.Name = a[mapping.JSONColumnName].(string)
        case "Age":
            o.Age = a[mapping.JSONColumnName].(float64)
  1. 我认为将映射附加到 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:

  1. 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)
  1. 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!

huangapple
  • 本文由 发表于 2022年11月21日 07:01:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/74512691.html
匿名

发表评论

匿名网友

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

确定