Home > Backend Development > Golang > How to Preserve Custom Marshalling in Go Embedded Structs?

How to Preserve Custom Marshalling in Go Embedded Structs?

DDD
Release: 2024-12-17 19:07:10
Original
854 people have browsed it

How to Preserve Custom Marshalling in Go Embedded Structs?

Preserving Custom Marshalling for Embedded Structs

In Go, embedding one struct into another is a common way to inherit functionality. However, when the embedded struct has a custom MarshalJSON() method, issues can arise. This article explores a solution to this challenge, ensuring that the outer struct can marshal its fields normally while still leveraging the custom marshalling of the embedded struct.

Consider the following structs:

type Person struct {
    Name string `json:"name"`
}

type Employee struct {
    *Person
    JobRole string `json:"jobRole"`
}
Copy after login

Normally, marshalling an Employee to JSON would produce the expected output:

p := Person{"Bob"}
e := Employee{&p, "Sales"}
output, _ := json.Marshal(e)
fmt.Printf("%s\n", string(output))
// Output: {"name":"Bob","jobRole":"Sales"}
Copy after login

However, introducing a custom MarshalJSON() method for the embedded Person struct changes this behavior:

func (p *Person) MarshalJSON() ([]byte, error) {
    return json.Marshal(struct{ Name string `json:"name"` }{Name: strings.ToUpper(p.Name)})
}
Copy after login

Now, marshalling the Employee produces only the uppercased name:

output, _ := json.Marshal(e)
fmt.Printf("%s\n", string(output))
// Output: {"name":"BOB"}
Copy after login

To resolve this, one might attempt to add a MarshalJSON() method to the outer Employee struct. However, this approach requires knowledge of the embedded type's custom marshalling, which may not always be practical.

A more generic solution involves directly implementing MarshalJSON() on the outer type:

// Note: not on Person
func (e *Employee) MarshalJSON() ([]byte, error) {
    inner, err := json.MarshalIndent((*e.Person).(*Person), "", "    ")
    if err != nil {
        return nil, err
    }

    b := []byte(strings.Replace(string(inner), "}", "}", -1))
    b = append(b, []byte(`,"jobRole":"`+e.JobRole+`"}`)...)

    return b, nil
}
Copy after login

This approach calls the embedded struct's MarshalJSON() method, converts the result to a map, and adds the outer struct's fields to produce the desired JSON output. Note that it does not manipulate the embedded struct's custom marshalling.

Alternatively, one can use a reflection-based approach:

func (e *Employee) MarshalJSON() ([]byte, error) {
    v := reflect.ValueOf(e).Elem()
    vf := v.FieldByName("Person")
    tmp, err := json.MarshalIndent(vf.Interface(), "", "    ")
    if err != nil {
        return nil, err
    }

    return []byte(strings.Replace(string(tmp), "}", `,"jobRole":"`+e.JobRole+`"}`, -1)), nil
}
Copy after login

This method uses reflection to access the embedded struct's value and field, enabling custom marshalling without relying on structural knowledge.

By implementing MarshalJSON() on the outer type, this approach ensures that both the embedded and outer struct's fields are marshaled correctly, preserving the desired output.

The above is the detailed content of How to Preserve Custom Marshalling in Go Embedded Structs?. 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
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template