What is the way to get the json field names of this struct ?
type example struct {
Id int `json:"id"`
CreatedAt string `json:"created_at"`
Tag string `json:"tag"`
Text string `json:"text"`
AuthorId int `json:"author_id"`
}
I try to print the fields with this function :
func (b example) PrintFields() {
val := reflect.ValueOf(b)
for i := 0; i < val.Type().NumField(); i++ {
fmt.Println(val.Type().Field(i).Name)
}
}
Of course I get :
Id
CreatedAt
Tag
Text
AuthorId
But I would like something like :
id
created_at
tag
text
author_id
You use the StructTag type to get the tags. The documentation I linked has examples, look them up, but your code could be something like
func (b example) PrintFields() {
val := reflect.ValueOf(b)
for i := 0; i < val.Type().NumField(); i++ {
fmt.Println(val.Type().Field(i).Tag.Get("json"))
}
}
NOTE The json
tag format supports more than just field names, such as omitempty
or string
, so if you need an approach that takes care of that too, further improvements to the PrintFields
function should be made:
json
tag is -
(i.e. json:"-"
)Something like this:
func (b example) PrintFields() {
val := reflect.ValueOf(b)
for i := 0; i < val.Type().NumField(); i++ {
t := val.Type().Field(i)
fieldName := t.Name
if jsonTag := t.Tag.Get("json"); jsonTag != "" && jsonTag != "-" {
if commaIdx := strings.Index(jsonTag, ","); commaIdx > 0 {
fieldName = jsonTag[:commaIdx]
}
}
fmt.Println(fieldName)
}
}
Use:
func (b example) PrintFields() {
val := reflect.ValueOf(b)
t := val.Type()
for i := 0; i < t.NumField(); i++ {
fmt.Println(t.Field(i).Tag.Get("json"))
}
}
See it in playground.
Instead of using StructField
's Name
, you can use Tag
to get a StructTag
object. See: https://golang.org/pkg/reflect/#StructTag
Then you can use StructTag
's Get
or Lookup
methods to get the json tag:
Using Get
:
func (b example) PrintFields() {
val := reflect.ValueOf(b)
for i := 0; i < val.Type().NumField(); i++ {
// prints empty line if there is no json tag for the field
fmt.Println(val.Type().Field(i).Tag.Get("json"))
}
}
Using Lookup
:
func (b example) PrintFields() {
val := reflect.ValueOf(b)
for i := 0; i < val.Type().NumField(); i++ {
// skips fields without json tag
if tag, ok := val.Type().Field(i).Tag.Lookup("json"); ok {
fmt.Println(tag)
}
}
}
Not the Name
you are looking for. What you looking is the Tag
func (b example) PrintFields() {
val := reflect.ValueOf(b)
for i := 0; i < val.Type().NumField(); i++ {
fmt.Println(val.Type().Field(i).Tag.Get("json"))
}
}
an updated version with a generic interface as parameter:
func PrintFields(b interface{}) {
val := reflect.ValueOf(b)
for i := 0; i < val.Type().NumField(); i++ {
t := val.Type().Field(i)
fieldName := t.Name
if jsonTag := t.Tag.Get("json"); jsonTag != "" && jsonTag != "-" {
// check for possible comma as in "...,omitempty"
var commaIdx int
if commaIdx = strings.Index(jsonTag, ","); commaIdx < 0 {
commaIdx = len(jsonTag)
}
fieldName = jsonTag[:commaIdx]
}
fmt.Println(fieldName)
}
}