Skip to content

Instantly share code, notes, and snippets.

@bxcodec
Last active July 31, 2024 21:43
Show Gist options
  • Save bxcodec/c2a25cfc75f6b21a0492951706bc80b8 to your computer and use it in GitHub Desktop.
Save bxcodec/c2a25cfc75f6b21a0492951706bc80b8 to your computer and use it in GitHub Desktop.
Golang Struct To Map Example By JSON tag
/*
This function will help you to convert your object from struct to map[string]interface{} based on your JSON tag in your structs.
Example how to use posted in sample_test.go file.
*/
func structToMap(item interface{}) map[string]interface{} {
res := map[string]interface{}{}
if item == nil {
return res
}
v := reflect.TypeOf(item)
reflectValue := reflect.ValueOf(item)
reflectValue = reflect.Indirect(reflectValue)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
for i := 0; i < v.NumField(); i++ {
tag := v.Field(i).Tag.Get("json")
field := reflectValue.Field(i).Interface()
if tag != "" && tag != "-" {
if v.Field(i).Type.Kind() == reflect.Struct {
res[tag] = structToMap(field)
} else {
res[tag] = field
}
}
}
return res
}
package sample_test
import (
"encoding/json"
"fmt"
"testing"
"github.com/stretchr/testify/require"
)
type SampleStruct struct {
Name string `json:"name"`
ID string `json:"id"`
}
type EmbededStruct struct {
FieldStruct `json:"field"`
Hello string `json:"hello"`
}
type FieldStruct struct {
OnePoint string `json:"one_point"`
Sample *SampleStruct `json:"sample"`
}
func TestStructToMap_Normal(t *testing.T) {
sample := SampleStruct{
Name: "John Doe",
ID: "12121",
}
res := structToMap(sample)
require.NotNil(t, res)
fmt.Printf("%+v \n", res)
// Output: map[name:John Doe id:12121]
jbyt, err := json.Marshal(res)
require.NoError(t, err)
fmt.Println(string(jbyt))
// Output: {"id":"12121","name":"John Doe"}
}
func TestStructToMap_FieldStruct(t *testing.T) {
sample := &SampleStruct{
Name: "John Doe",
ID: "12121",
}
field := FieldStruct{
Sample: sample,
OnePoint: "yuhuhuu",
}
res := structToMap(field)
require.NotNil(t, res)
fmt.Printf("%+v \n", res)
// Output: map[sample:0xc4200f04a0 one_point:yuhuhuu]
jbyt, err := json.Marshal(res)
require.NoError(t, err)
fmt.Println(string(jbyt))
// Output: {"one_point":"yuhuhuu","sample":{"name":"John Doe","id":"12121"}}
}
func TestStructToMap_EmbeddedStruct(t *testing.T) {
sample := &SampleStruct{
Name: "John Doe",
ID: "12121",
}
field := FieldStruct{
Sample: sample,
OnePoint: "yuhuhuu",
}
embed := EmbededStruct{
FieldStruct: field,
Hello: "WORLD!!!!",
}
res := structToMap(embed)
require.NotNil(t, res)
fmt.Printf("%+v \n", res)
//Output: map[field:map[one_point:yuhuhuu sample:0xc420106420] hello:WORLD!!!!]
jbyt, err := json.Marshal(res)
require.NoError(t, err)
fmt.Println(string(jbyt))
// Output: {"field":{"one_point":"yuhuhuu","sample":{"name":"John Doe","id":"12121"}},"hello":"WORLD!!!!"}
}
@ahmadissa
Copy link

ahmadissa commented May 1, 2020

this will fail on more complex struct as below, mainly in the slice of struct part

type playlist struct {
	CreatedOn   string `json:"createdOn"`
	Duration    int64  `json:"duration"`
	DurationStr string `json:"duration_str"`
	HasLayout   bool   `json:"hasLayout"`
	Img         string `json:"img"`
	Layout      struct {
		Default    bool   `json:"Default"`
		Horizontal bool   `json:"Horizontal"`
		ID         string `json:"ID"`
		Layers     []struct {
			Height       int64  `json:"Height"`
			Horizontal   bool   `json:"Horizontal"`
			ID           string `json:"ID"`
			LayerID      string `json:"LayerID"`
			Left         int64  `json:"Left"`
			Top          int64  `json:"Top"`
			Vertical     bool   `json:"Vertical"`
			Width        int64  `json:"Width"`
			Img          string `json:"img"`
			StretchToFit bool   `json:"stretchToFit"`
			Thumb256     string `json:"thumb_256"`
		} `json:"Layers"`
		Vertical bool   `json:"Vertical"`
		Name     string `json:"name"`
		Playlist string `json:"playlist"`
	} `json:"layout"`
	ManualControl  bool   `json:"manualControl"`
	MediaNo        int64  `json:"media_no"`
	Name           string `json:"name"`
	ResetTimeout   int64  `json:"resetTimeout"`
	ShowNav        bool   `json:"showNav"`
	Size           int64  `json:"size"`
	SizeStr        string `json:"size_str"`
	Storage        string `json:"storage"`
	TapToStart     bool   `json:"tapToStart"`
	TapToStartText string `json:"tapToStartText"`
	ThumbURL       string `json:"thumbURL"`
	Transition     string `json:"transition"`
	Type           string `json:"type"`
}

@ahmadissa
Copy link

The below worked for me

func structToMap(data interface{}) (map[string]interface{}, error) {
	dataBytes, err := json.Marshal(data)
	if err != nil {
		return nil, err
	}
	mapData := make(map[string]interface{})
	err = json.Unmarshal(dataBytes, &mapData)
	if err != nil {
		return nil, err
	}
	return mapData, nil
}

@junaid-ali
Copy link

@ahmadissa I'm using the similar approach but I was wondering if we could directly convert struct to map without involving []byte

@vashish1
Copy link

This will also fail, if the json tag includes "omitempty"

for example:
type User struct {
Uid string json:"uid,omitempty"
Name string json:"name,omitempty"
Email string json:"email,omitempty"
Mobile_no string json:"mobile_no,omitempty"
Shortlisted []ShortList json:"shortlisted,omitempty"
}

the resulted json key insuch case will be mobile_no,omitempty

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment