Custom JSON Marshaling
Default JSON Encoding
Go has a default JSON package that pretty much solves most of our problems. Here's a quick reminder on how it works
If we convert the bytes into string, we will see the following.
Similarly, if we have a JSON text string, we convert it into bytes and we can unmarshal the data back into a struct.
Custom JSON Encoding
However, there are times we want to change how data are being shown to users. For example, perhaps users don't really want to know the dog age in human years, instead they prefer to see it in dog years. We can write a custom JSON marshaller to deal with this problem.
Why does it work? Let's take a look at what Go doc says about encoding/json
.
Marshal traverses the value v recursively. If an encountered value implements the Marshaler interface and is not a nil pointer, Marshal calls its MarshalJSON method to produce JSON. If no MarshalJSON method is present but the value implements encoding.TextMarshaler instead, Marshal calls its MarshalText method and encodes the result as a JSON string. The nil pointer exception is not strictly necessary but mimics a similar, necessary exception in the behavior of UnmarshalJSON.
When we implement MarshalJSON
on Dog
struct, Dog
becomes a Marshaler
. Similarly, we can do the same for Unmarshal
.
Better Approach
Obviously it'd be very cumbersome to write the custom marshal methods if a struct has many fields. We can use Golang composition, i.e. struct embedding, to reduce the unnecessary lines of code.
Notice the Alias
structs, they are for preventing MarshalJSON
being called infinitely. If we declare aux
with the type Dog
, when we perform json.Marshal
inside MarshalJSON
, MarshalJSON
is called again, and the loop goes on infinitely. The DogAlias
type has all the fields of the original Dog
type but none of the original methods.
Last updated