Skip to content

Instantly share code, notes, and snippets.

@rohanthewiz
Created November 12, 2020 06:21
Show Gist options
  • Save rohanthewiz/d4ca16baa5099506370f23a1418f73d8 to your computer and use it in GitHub Desktop.
Save rohanthewiz/d4ca16baa5099506370f23a1418f73d8 to your computer and use it in GitHub Desktop.
JSON Marshal based on custom struct tags
package main
import (
"encoding/json"
"fmt"
"reflect"
)
type User struct {
Username string `json:"user" db:"username"`
DisplayName string `json:"displayName" db:"display_name"`
Email string `json:"email"`
}
// - Unmarshalled from UI <-- {"user": "user123", "displayName": "John Brown","email": "johnbrown@usa.com"}
// - Marshalled for DB --> {"username":"user123","display_name":"John Brown","email":"johnbrown@usa.com"}
func main() {
var user User
const userAsString = `{"user": "user123", "displayName": "John Brown","email": "johnbrown@usa.com"}`
err := json.Unmarshal([]byte(userAsString), &user)
if err != nil {
fmt.Println(err)
}
jsonByte, err := json.Marshal(&user)
if err != nil {
fmt.Println(err)
}
fmt.Println(string(jsonByte))
}
func (u *User) MarshalJSON() ([]byte, error) {
// Get old struct fields
uType := reflect.TypeOf(u).Elem()
var fields []reflect.StructField
// Scan and collect all fields converting any that have a "db" tag
for i := 0; i < uType.NumField(); i++ {
f := uType.Field(i)
if dbkey, ok := f.Tag.Lookup("db"); ok && dbkey != "" {
f.Tag = reflect.StructTag(fmt.Sprintf(`json:"%s"`, dbkey))
}
fields = append(fields, f)
}
newType := reflect.StructOf(fields)
newTypeInstance := reflect.New(newType).Elem()
origInstance := reflect.ValueOf(u).Elem()
// Copy over the values
for i := 0; i < origInstance.NumField(); i++ {
newTypeInstance.Field(i).Set(origInstance.Field(i))
}
return json.Marshal(newTypeInstance.Interface())
// Manual method picking out a few fields
// userNameField, ok := uType.FieldByName("Username")
// if !ok { return nil, errors.New("could not find Username field") }
// // Manipulate username field struct tag
// dbTagUser, _ := userNameField.Tag.Lookup("db")
// fmt.Printf("dbTagUser %#v\n", dbTagUser)
// if dbTagUser != "" {
// userNameField.Tag = reflect.StructTag(fmt.Sprintf(`json:"%s"`, dbTagUser))
// }
//
// fldDisplayName, ok := uType.FieldByName("DisplayName")
// if !ok { return nil, errors.New("could not find DisplayName field") }
// // Manipulate username field struct tag
// dbTagDisplayName, _ := fldDisplayName.Tag.Lookup("db")
// if dbTagDisplayName != "" {
// fldDisplayName.Tag = reflect.StructTag(fmt.Sprintf(`json:"%s"`, dbTagDisplayName))
// }
//
// fldEmail, _ := uType.FieldByName("Email")
//
// // Make a new struct from the provided fields. Fields must match original so copy below can work
//
// newType := reflect.StructOf([]reflect.StructField{userNameField, fldDisplayName, fldEmail})
//
// // Copy over the values
// origInstance := reflect.ValueOf(u).Elem()
// newTypeInstance := reflect.New(newType).Elem()
// for i := 0; i < origInstance.NumField(); i++ {
// newTypeInstance.Field(i).Set(origInstance.Field(i))
// }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment