Home > Backend Development > Golang > How to Add Arbitrary Fields to the JSON Output of an Unknown Struct in Go?

How to Add Arbitrary Fields to the JSON Output of an Unknown Struct in Go?

Linda Hamilton
Release: 2024-12-29 17:47:10
Original
432 people have browsed it

How to Add Arbitrary Fields to the JSON Output of an Unknown Struct in Go?

Adding Arbitrary Fields to JSON Output of an Unknown Struct

Introduction

Embedding structs as anonymous closures is a common approach to adding extra fields to JSON outputs. However, this technique is limited to situations where the struct type is known.

The Problem: Embedding Unknown Types

When dealing with arbitrary structs or interfaces, the traditional embedding approach fails. Consider the following code:

type example interface{}
type Data struct {
    Name string
}

type Extra struct {
    Text string
}

func printInterface(val interface{})    {
    example1 := struct {
        example
        Extra string
    }{
        example: val,
        Extra: "text",
    }
    json.NewEncoder(os.Stdout).Encode(example1)
}

func main() {
    d := Data{Name:"name"}
    printInterface(&d)
}
Copy after login

This code produces the following JSON output:

{"example":{"Name":"name"},"Extra":"text"}
Copy after login

As you can see, the Name field of the Data struct is not included in the JSON output. This is because interfaces do not have fields, and thus the fields of the underlying struct are not promoted.

Dynamically Generating a Struct Type

One solution is to dynamically generate a new struct type using reflection. This struct will contain an anonymous field of the unknown type and an additional field for the extra data.

func printInterface(val interface{}) {
    t2 := reflect.StructOf([]reflect.StructField{
        reflect.StructField{
            Name:      "X",
            Anonymous: true,
            Type:      reflect.TypeOf(val),
        },
        reflect.StructField{
            Name: "Extra",
            Type: reflect.TypeOf(""),
        },
    })

    v2 := reflect.New(t2).Elem()
    v2.Field(0).Set(reflect.ValueOf(val))
    v2.FieldByName("Extra").SetString("text")

    json.NewEncoder(os.Stdout).Encode(v2.Interface())
}
Copy after login

This code produces the desired JSON output:

{"Name":"name","Extra":"text"}
Copy after login

Marshaling Twice

Another alternative is to marshal the unknown value, unmarshal it into a map, add the extra field, and marshal the map back into JSON.

func printInterface(val interface{}) error {
    data, err := json.Marshal(val)
    if err != nil {
        return err
    }

    v2 := map[string]interface{}{}
    if err := json.Unmarshal(data, &v2); err != nil {
        return err
    }

    v2["Extra"] = "text"
    return json.NewEncoder(os.Stdout).Encode(v2)
}
Copy after login

This solution is simpler but may be less efficient due to the double marshaling process.

The above is the detailed content of How to Add Arbitrary Fields to the JSON Output of an Unknown Struct 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