Reputation: 14403
I need to marshal/unmarshal json to struct in golang. Assume the struct is
type A struct {
Id string `json:"id"`
Version string `json:"version"`
Actors []actor `json:"actors`
Payload struct {
Name string `json:"name"`
Number string `json:"number"`
}
}
type payload struct {
Name string `json:"name"`
Number string `json:"number"`
}
type actor struct {
Id string `json:"id"`
Type string `json:"type"`
Role string `json:"role"`
}
The actors or payload maybe empty. The json maybe
{
"id": "78a07cea-be2b-499c-b82b-e4f510260484",
"version": "1.0.0",
"actors": [
{
"id": "1234567",
"type": "XXX",
"role": "111"
},
{
"id": "7654321",
"type": "YYY",
"role": "222"
}
],
"payload": ""
}
or
{
"id": "78a07cea-be2b-499c-b82b-e4f510260484",
"version": "1.0.0",
"actors": [],
"payload": {
"name": "XXXX",
"number": "1234567"
}
}
If i follow the struct A design and try to marshal json with payload empty, i have to init as below
a := A{
Id: "78a07cea-be2b-499c-b82b-e4f510260484",
Version: "1.0.0",
Actors: []actor{
actor{
Id: "1234567",
Type: "XXX",
Role: "111",
},
actor{
Id: "7654321",
Type: "YYY",
Role: "222",
},
},
Payload: payload{},
}
Which will result in below json with one empty payload struct
{
"id": "78a07cea-be2b-499c-b82b-e4f510260484",
"version": "1.0.0",
"actors": [
{
"id": "1234567",
"type": "XXX",
"role": "111"
},
{
"id": "7654321",
"type": "YYY",
"role": "222"
}
],
"payload": {
"name":"",
"number":""
}
}
Is there any way i can generate
"payload": ""
instead of blank payload struct? Or is there any other struct design for this kind of json format? BTW i cannot pass nil to Payload struct.
Upvotes: 0
Views: 649
Reputation: 31701
The json.Marshaler interface can be implemented to customize JSON encoding, and the json.Unmarshaler interface for decoding (left as an exercise for the reader):
package main
import (
"encoding/json"
"fmt"
)
type A struct {
Payload payload
}
type payload struct {
Name string `json:"name"`
Number string `json:"number"`
}
func (p payload) MarshalJSON() ([]byte, error) {
if p.Name == "" && p.Number == "" {
return []byte(`""`), nil
}
type _payload payload // prevent recursion
return json.Marshal(_payload(p))
}
func main() {
var a A
b, _ := json.MarshalIndent(a, "", " ")
fmt.Println(string(b))
a.Payload.Name = "foo"
b, _ = json.MarshalIndent(a, "", " ")
fmt.Println(string(b))
}
// Output:
// {
// "Payload": ""
// }
// {
// "Payload": {
// "name": "foo",
// "number": ""
// }
// }
Try it on the playground: https://play.golang.org/p/9jhSWnKTnTf
The ad-hoc _payload
type is required to prevent recursion. If one would write return json.Marshal(p)
, the json package would call MarshalJSON
again, because p is of type payload
, and payload
implements json.Marshaler.
The _payload
type has the same underlying type as payload
but does not implement json.Marshaler (see Type definitions for details), so it is encoded using the standard rules of the json package; it produces exactly the same output that encoding a value of type payload
would produce if payload
didn't implement json.Marshaler.
Upvotes: 4
Reputation: 3604
Check if using omitempty
with json struct tag helps. I think it will result in "payload": {}
instead of "payload": ""
Upvotes: 1