I have a struct that looks like this:
type Type int
const (
A Type = iota
B
C
)
type Character struct {
Type Type `json:"type"`
}
When I call json.Marshal(...)
on the struct, is there a way that the json:"type"
representation is a string called either "A"
, "B"
, or "C
"?
When this is presented in JSON, nobody is going to know what 0
, 1
, or 2
is, so the name of the constant is more useful.
Apologies if this has been asked before. I googled all over and couldn't find anything.
Here is an example:
type Type int
const (
A Type = iota
B
C
)
type Character struct {
Type Type `json:"type,string"`
}
func main() {
c := Character{}
c.Type = A
j, err := json.Marshal(c)
if err != nil {
panic(err)
}
fmt.Println(string(j))
}
I want fmt.Println(string(j))
to print {"type":"A"}
, not {"type":0}
.
You need to define a custom marshaller for your type.
type Type int
const (
A Type = iota
B
C
)
var typeToString = map[Type]string{
A: "A",
B: "B",
C: "C",
}
func (t Type) MarshalJSON() ([]byte, error) {
return json.Marshal(typeToString[t])
}
type Character struct {
Type Type `json:"type"`
}
func main() {
c := Character{}
c.Type = A
j, err := json.Marshal(c)
if err != nil {
panic(err)
}
fmt.Println(string(j))
}
The function MarshalJSON
defines how json.Marshal
should marshal your type. You can do something similar for unmarshaling if you need to go the other direction as well.
So your JSON API gives you the type A:
I want fmt.Println(string(j)) to print {"type":"A"}, not {"type":0}.
You could change your code like this, then your API works:
https://play.golang.org/p/ypvFvQpBw-C
type JSONType string
const (
A JSONType = "A"
B JSONType = "B"
C JSONType = "C"
)
type Character struct {
JSONType JSONType `json:"type,string"`
}
func main() {
c := Character{}
c.JSONType = A
j, err := json.Marshal(c)
if err != nil {
panic(err)
}
fmt.Println(string(j))
}
Short reply: there's NO direct option to achieve your goal.
Long reply: truth is, you can actually override the way Go can encode structs.
Here's the working code:
https://play.golang.org/p/i92pUpNG-Wr
package main
import (
"encoding/json"
"fmt"
)
// please consider to rename this!
type Type int
const (
A Type = iota
B
C
)
type Character struct {
Type Type `json:"-"`
}
func (c *Character) mapTypeToString() string {
switch c.Type {
case B:
return "B"
case C:
return "C"
}
// defaults on A
return "A"
}
// MarshalJSON overwrites the standard JSON marshal.
func (c *Character) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
Type string `json:"type"`
}{
Type: c.mapTypeToString(),
})
}
func main() {
c := &Character{}
c.Type = A
j, err := json.Marshal(c)
if err != nil {
panic(err)
}
fmt.Println(string(j))
}
Be aware of the c := &Character{}
initialization.
The tradeoff would be to have the mapTypeToString()
method that needs to be updated according to the different types of ... Type.
Please, also consider to avoid naming structs and vars like Type
:)