Golang Unmarshal with different set of structural tags

WBOY
Release: 2024-02-09 23:10:09
forward
474 people have browsed it

具有不同结构标签集的 Golang Unmarshal

php editor Baicao today introduces to you a powerful Golang feature - Unmarshal with different structural tag sets. In Golang programming, Unmarshal is a process of converting data into a structure. However, when our data source contains different sets of structural tags, the traditional Unmarshal method may not meet the needs. Therefore, we need to use Golang Unmarshal with a different set of structural tags to achieve this functionality. This article will introduce in detail the usage and precautions of this feature. Let’s explore together!

Question content

I am using a third party tool's api which has custom key names in its json. I also have to use the api on two different environments (production and staging). Unfortunately, the custom fields in the api have different key names in both environments to represent the same data. In the example below, the json keycustom-1in the production environment is exactly the same as the json keycustom-7in the staging environment. I want to unmarshal any of them into the same data structure but I don't know how. I was hoping there was a way to somehow override thejson.unmarshal()function for tags that usejsonon prod, but usejsonstaging# when staging ##. To me, this makes the most sense and is the simplest solution. I guess I'll have to write a customunmarshaljson(data []byte) errorfunction for myjsonobjtype, but again, I don't know how to achieve what I want in a custom function the behavior of. Can anyone point me in the right direction, some documentation, or some examples I can use?

package main import ( "encoding/json" "fmt" ) type jsonobj struct { id string `json:"custom-1" jsonstaging:"custom-7"` desc string `json:"custom-2" jsonstaging:"custom-8"` } func (i jsonobj) string() string { return fmt.sprintf(`{ id: "%s", desc: "%s" }`, i.id, i.desc) } func main() { var jsonprod = `{ "custom-1": "object-a", "custom-2": "test" } ` var jsonstaging = `{ "custom-7": "object-a", "custom-8": "test" } ` var jsonobjprod jsonobj var jsonobjstaging jsonobj json.unmarshal([]byte(jsonprod), &jsonobjprod) json.unmarshal([]byte(jsonstaging), &jsonobjstaging) fmt.println("production: ", jsonobjprod) fmt.println("staging: ", jsonobjstaging) }
Copy after login

When I run it with go run I get

production: { id: "object-a", desc: "test" } staging: { id: "", desc: "" }
Copy after login

This is what my current code is expecting, but I would like to get

Production: { Id: "object-a", Desc: "test" } Staging: { Id: "object-a", Desc: "test" }
Copy after login

I cannot modify the api of the staging or production environment.

I've tried creating different structures and interfaces, but as the number of fields (and custom json keys) increases (and they grow) it seems to be a maintenance nightmare. Please help me if this is the only way, I didn't get it to work either before I decided this might not be the right path.

Workaround

For future reference, if anyone wants to do this, I think I found a way using the built-in

reflectpackage.

First you have to use the json.unmarshal() function but populate the

map[string] interface{}instead of the object you want to build.

Then I wrote a function to get the environment and map. It loops through all the fields in the new instance of the actual object (not the map) and gets the label for the environment you're using. It then sets the field in the new object to

objmap[tag].( ) . After setting all the fields with labels it will return the new object.

This is my working code:

package main import ( "encoding/json" "fmt" "reflect" ) const ( StagingStructTag = "jsonStaging" ProductionStructTag = "json" ) type jsonObj struct { Id string `json:"custom-1" jsonStaging:"custom-7"` Desc string `json:"custom-2" jsonStaging:"custom-8"` } func (i jsonObj) String() string { return fmt.Sprintf(`{ Id: "%s", Desc: "%s" }`, i.Id, i.Desc) } func main() { var jsonProd = `{ "custom-1": "object-a", "custom-2": "test" } ` var jsonStaging = `{ "custom-7": "object-a", "custom-8": "test" } ` var env string = "staging" var jsonObjProd jsonObj var jsonObjStaging jsonObj var jsonObjProdMap map[string]interface{} var jsonObjStagingMap map[string]interface{} json.Unmarshal([]byte(jsonStaging), &jsonObjStagingMap) json.Unmarshal([]byte(jsonProd), &jsonObjProdMap) jsonObjStaging = BuildJsonObj(env, jsonObjStagingMap) env = "production" jsonObjProd = BuildJsonObj(env, jsonObjProdMap) fmt.Println("Production: ", jsonObjProd) fmt.Println("Staging: ", jsonObjStaging) } func BuildJsonObj(env string, objMap map[string]interface{}) jsonObj { var obj jsonObj var t reflect.Type = reflect.TypeOf(obj) var structTagName string if env == "staging" { structTagName = StagingStructTag } else if env == "production" { structTagName = ProductionStructTag } for i := 0; i < t.NumField(); i++ { var field reflect.StructField = t.Field(i) var tag string var ok bool if tag, ok = field.Tag.Lookup(structTagName); ok { switch field.Name { case "Id": obj.Id = objMap[tag].(string) case "Desc": obj.Desc = objMap[tag].(string) } } } return obj }
Copy after login

The above is the detailed content of Golang Unmarshal with different set of structural tags. For more information, please follow other related articles on the PHP Chinese website!

source:stackoverflow.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!