Home > Backend Development > Golang > How to Customize JSON Unmarshaling with Reflection in Go?

How to Customize JSON Unmarshaling with Reflection in Go?

Susan Sarandon
Release: 2024-11-05 03:19:02
Original
590 people have browsed it

How to Customize JSON Unmarshaling with Reflection in Go?

Customizing JSON Unmarshaling with Reflection

In Go, unmarshalling JSON into a struct is a straightforward process. However, when dealing with fields that have custom tags, such as json:"some_field", the standard unmarshalling mechanism may not suffice.

One approach to handle this scenario is to use reflection. By inspecting the struct's fields using reflection, we can check if a field has a specific tag and if so, handle its unmarshalling accordingly.

In this particular case, we want to ensure that a field with the json tag is unmarshalled into a string field as-is. This allows us to handle JSON objects or arrays within our Go struct.

Example Scenario

Consider the following JSON data and Go struct:

<code class="json">{
  "I": 3,
  "S": {
    "phone": {
      "sales": "2223334444"
    }
  }
}</code>
Copy after login
<code class="go">type A struct {
    I int64
    S string `sql:"type:json"`
}</code>
Copy after login

Our goal is to unmarshal the "S" field as a string, preserving its nested JSON structure.

Solution Using Reflection

The following code demonstrates how to achieve this using reflection:

<code class="go">func main() {
    a := A{}

    // Unmarshal the JSON data into a byte slice
    var data []byte

    // Iterate over the fields of the struct
    typ := reflect.TypeOf(a)
    val := reflect.ValueOf(a)
    for i := 0; i < typ.NumField(); i++ {
        f := typ.Field(i)

        // Check if the field has a "json" tag
        if f.Tag.Get("json") == "" {
            continue
        }

        // Retrieve the field value
        fv := val.Field(i)

        // Unmarshall the JSON data into the field as a string
        if err := json.Unmarshal(data, &fv); err != nil {
            log.Fatal(err)
        }
    }

    fmt.Println(a)
}</code>
Copy after login

In this approach, we manually inspect each field of the struct using reflection to determine if it has the "json" tag. If it does, we unmarshal the JSON data into the field as a string.

Alternative Solution with Custom Marshaler and Unmarshaler

Another option is to implement a custom type, such as RawString, which implements the json.Marshaler and json.Unmarshaler interfaces. This allows for more flexibility and control over the unmarshalling process.

This approach is demonstrated in the following code:

<code class="go">// RawString is a raw encoded JSON object.
// It implements Marshaler and Unmarshaler and can
// be used to delay JSON decoding or precompute a JSON encoding.
type RawString string

// MarshalJSON returns *m as the JSON encoding of m.
func (m *RawString) MarshalJSON() ([]byte, error) {
    return []byte(*m), nil
}

// UnmarshalJSON sets *m to a copy of data.
func (m *RawString) UnmarshalJSON(data []byte) error {
    if m == nil {
        return errors.New("RawString: UnmarshalJSON on nil pointer")
    }
    *m += RawString(data)
    return nil
}

const data = `{"i":3, "S":{"phone": {"sales": "2223334444"}}}`

type A struct {
    I int64
    S RawString `sql:"type:json"`
}

func main() {
    a := A{}
    err := json.Unmarshal([]byte(data), &a)
    if err != nil {
        log.Fatal("Unmarshal failed", err)
    }
    fmt.Println("Done", a)
}</code>
Copy after login

By implementing our own type, we can customize the unmarshalling process and avoid the need for reflection, resulting in a cleaner and more efficient solution.

The above is the detailed content of How to Customize JSON Unmarshaling with Reflection in Go?. For more information, please follow other related articles on the PHP Chinese website!

source:php.cn
Statement of this Website
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
Latest Articles by Author
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template