Sling Academy
Home/Golang/Creating Custom Marshaling and Unmarshaling Logic in Go

Creating Custom Marshaling and Unmarshaling Logic in Go

Last updated: November 26, 2024

Go’s JSON package (encoding/json) provides straightforward capabilities for marshaling and unmarshaling data structures. However, certain scenarios require customization, such as handling non-standard JSON formats or manipulating data during these transformations. Here, we'll explore how to implement custom marshaling and unmarshaling logic.

Marshaling and Unmarshaling Basics

Let's start with the basics. Marshaling is the process of converting Go data structures to JSON. Unmarshaling is the reverse, converting JSON data into Go data structures.

package main

import (
    "encoding/json"
    "fmt"
)

type User struct {
    Name string
    Age  int
}

func main() {
    // Marshaling: Go struct to JSON
    user := User{Name: "Alice", Age: 30}
    jsonData, _ := json.Marshal(user)
    fmt.Println(string(jsonData))

    // Unmarshaling: JSON to Go struct
    jsonString := `{"Name":"Bob","Age":25}`
    var newUser User
    json.Unmarshal([]byte(jsonString), &newUser)
    fmt.Println(newUser)
}

Custom Marshaling

To implement custom marshaling, a data type must implement the json.Marshaler interface, which requires the MarshalJSON() method.

package main

import (
    "encoding/json"
    "fmt"
)

type Employee struct {
    Name     string
    Salary   int
    Position string
}

func (e Employee) MarshalJSON() ([]byte, error) {
    type Alias Employee // create an alias to avoid recursive calls
    return json.Marshal(&struct {
        Position string `json:"role"`
        Alias
    }{
        Position: e.Position,
        Alias:    (Alias)(e),
    })
}

func main() {
    emp := Employee{Name: "Charlie", Salary: 50000, Position: "Engineer"}
    jsonData, _ := json.Marshal(emp)
    fmt.Println(string(jsonData)) // Output: {"Name":"Charlie","Salary":50000,"role":"Engineer"}
}

In this example, we changed the field name Position to role in the JSON output, showcasing a field renaming customization.

Custom Unmarshaling

To enact custom unmarshaling behavior, implement the json.Unmarshaler interface, which involves the UnmarshalJSON() method.

package main

import (
    "encoding/json"
    "fmt"
)

type Account struct {
    ID     int    `json:"id"`
    Name   string `json:"name"`
    Active bool   `json:"active"`
}

func (a *Account) UnmarshalJSON(data []byte) error {
    var temp struct {
        ID     int    `json:"id"`
        Name   string `json:"name"`
        Status string `json:"status"`
    }
    if err := json.Unmarshal(data, &temp); err != nil {
        return err
    }
    a.ID = temp.ID
    a.Name = temp.Name
    a.Active = (temp.Status == "active") // Converts status string to boolean
    return nil
}

func main() {
    jsonString := `{"id":1,"name":"Roy","status":"active"}`
    var acc Account
    json.Unmarshal([]byte(jsonString), &acc)
    fmt.Println(acc) // Output: {1 Roy true}
}

This example demonstrates custom behavior during unmarshaling, where a string field status from the JSON is converted into a boolean field Active in Go.

Combining Both Techniques

You can combine both custom marshaling and unmarshaling techniques in the same struct to handle complex data transformation requirements. This allows for full control over the JSON representation and parsing logic.

Customize these methods according to your application's needs to neatly control how data is transformed in and out of your Go programs.

Next Article: Handling Large JSON Files Efficiently in Go

Previous Article: Comparing JSON, XML, and Binary Serialization Performance in Go

Series: Data Serialization and Encoding in Go

Golang

Related Articles

You May Also Like

  • How to remove HTML tags in a string in Go
  • How to remove special characters in a string in Go
  • How to remove consecutive whitespace in a string in Go
  • How to count words and characters in a string in Go
  • Relative imports in Go: Tutorial & Examples
  • How to run Python code with Go
  • How to generate slug from title in Go
  • How to create an XML sitemap in Go
  • How to redirect in Go (301, 302, etc)
  • Using Go with MongoDB: CRUD example
  • Auto deploy Go apps with CI/ CD and GitHub Actions
  • Fixing Go error: method redeclared with different receiver type
  • Fixing Go error: copy argument must have slice type
  • Fixing Go error: attempted to use nil slice
  • Fixing Go error: assignment to constant variable
  • Fixing Go error: cannot compare X (type Y) with Z (type W)
  • Fixing Go error: method has pointer receiver, not called with pointer
  • Fixing Go error: assignment mismatch: X variables but Y values
  • Fixing Go error: array index must be non-negative integer constant