Home >Backend Development >Golang >How to Unmarshal Dynamic JSON in Go without Generic Placeholder Fields?

How to Unmarshal Dynamic JSON in Go without Generic Placeholder Fields?

Patricia Arquette
Patricia ArquetteOriginal
2024-12-12 11:39:12934browse

How to Unmarshal Dynamic JSON in Go without Generic Placeholder Fields?

Unmarshalling Dynamic JSON Based on a Type Key

Introduction

Unmarshalling JSON data into a Go struct can be a straightforward task. However, when dealing with JSON documents that contain dynamic data structures, where the type of a field can vary, the process can become more complex. This article explores a solution to this challenge without introducing generic placeholder fields.

Problem Definition

Consider the following JSON spec:

{
  "some_data": "foo",
  "dynamic_field": { "type": "A", "name": "Johnny" },
  "other_data": "bar"
}
{
  "some_data": "foo",
  "dynamic_field": { "type": "B", "address": "Somewhere" },
  "other_data": "bar"
}

Both JSON documents should be unmarshalled into the same Go struct:

type BigStruct struct {
  SomeData     string    `json:"some_data"`
  DynamicField Something `json:"dynamic_field"`
  OtherData    string    `json:"other_data"`
}

The key question is: how to create the Something type and implement the unmarshalling logic?

Solution: Using an Interface with Custom UnmarshalJSON Method

The solution involves creating an interface for the Something type:

type Something interface {
  GetType() string
}

Next, define specific struct types that implement the Something interface:

type BaseDynamicType struct {
  Type string `json:"type"`
}

type DynamicTypeA struct {
  BaseDynamicType
  Name string `json:"name"`
}

type DynamicTypeB struct {
  BaseDynamicType
  Address string `json:"address"`
}

The DynamicType interface method allows the JSON data to be unmarshalled into the appropriate structure:

func (d *DynamicType) UnmarshalJSON(data []byte) error {
    var typ struct {
        Type string `json:"type"`
    }
    if err := json.Unmarshal(data, &typ); err != nil {
        return err
    }
    switch typ.Type {
    case "A":
        d.Value = new(TypeA)
    case "B":
        d.Value = new(TypeB)
    }
    return json.Unmarshal(data, d.Value)
}

This method inspects the JSON data and creates an instance of TypeA or TypeB as needed.

Implementing UnmarshalJSON on the BigStruct

Finally, implement the UnmarshalJSON method on the BigStruct type:

func (b *BigStruct) UnmarshalJSON(data []byte) error {
    var tmp BigStruct // avoids infinite recursion
    return json.Unmarshal(data, &tmp)
}

This method uses a temporary BigStruct type to avoid recursion and allows the dynamic field to be unmarshalled using the appropriate DynamicType type based on the type field in the JSON data.

Conclusion

This solution provides a clean and efficient way to unmarshal dynamic JSON data without the need for additional generic placeholder fields. By employing an interface and implementing custom UnmarshalJSON methods, the Go struct can adapt to the dynamic data structure in the JSON input.

The above is the detailed content of How to Unmarshal Dynamic JSON in Go without Generic Placeholder Fields?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn