3

There is struct of MyStruct.

type MyStruct struct {
    Code        int   `json:"Code"`
    Flags       uint8 `json:"Flags"`
    OptionField int   `json:",omitempty"`
}

Following code convert it to json.

f := MyStruct{Code:500, OptionField:41}
r, _ := json.Marshal(f)
fmt.Println(string(r)

I need to "OptionField" be optional. Some time it should exist in json with one of values [0, 1, 2, 3, ]. and in the other time it should exclude from json.

My problem is: omitempty will exclude it when the value is zero, and the default value of int is zero. Is there any way to omit field in condition (ex: omit if value is -1). Or there is any way to do it.

1

2 Answers 2

6

You could use *int instead of int and set the pointer value to nil in order to omit this.

package main

import (
    "encoding/json"
    "fmt"
)

type MyStruct struct {
    Code        int   `json:"Code"`
    Flags       uint8 `json:"Flags"`
    OptionField *int  `json:",omitempty"`
}

func format(s MyStruct) string {
    r, _ := json.Marshal(s)
    return string(r)
}

func main() {
    f := MyStruct{Code: 500, Flags: 10, OptionField: new(int)}
    fmt.Println(format(f)) // {"Code":500,"Flags":10,"OptionField":0}
    f.OptionField = nil
    fmt.Println(format(f)) // {"Code":500,"Flags":10}
}
Sign up to request clarification or add additional context in comments.

Comments

0

You can use some custom struct tags to filter out what you need into a map before marshaling to json. Using pointers for this can get messy fast besides being prone to bugs if each value is not carefully dereferenced.

I would recommend refactoring the simplified example to include a MapOptions struct that handles getting the tag for each available option so you can quickly enumerate and update all available map options instead of hard-coding the tag name as shown.

package main

import (
    "encoding/json"
    "fmt"

    "github.com/fatih/structs"
)

func main() {
    myStruct := MyStruct{
        Code:        500,
        Flags:       10,
        OptionField: 0,
    }

    json, _ := myStruct.ToJson("omitoptions")
    fmt.Printf("%s\n", json) // {"Code":500,"Flags":10}

    json, _ = myStruct.ToJson("omitempty")
    fmt.Printf("%s\n", json) // {"Code":500,"Flags":10}

    // entering an invalid tag, or no tag at all, defaults to "structs"
    json, _ = myStruct.ToJson("")
    fmt.Printf("%s\n", json) // {"Code":500,"Flags":10,"OptionField":0}
}

type MyStruct struct {
    Code        int   `structs:"Code" omitoptions:"Code" omitempty:"Code,omitempty"`
    Flags       uint8 `structs:"Flags" omitoptions:"Flags" omitempty:"Flags,omitempty"`
    OptionField int   `structs:"OptionField" omitoptions:"-" omitempty:"OptionField,omitempty"`
}

// ToMap converts the struct to a map, using the selected tag name to filter fields
func (c *MyStruct) ToMap(tag string) map[string]interface{} {
    s := structs.New(c)
    s.TagName = tag

    return s.Map()
}

// ToJson serializes the struct to a JSON byte slice, using the selected tag name
func (c *MyStruct) ToJson(tag string) ([]byte, error) {
    m := c.ToMap(tag)
    bytes, err := json.Marshal(m)
    if err != nil {
        return nil, err
    }

    return bytes, nil
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.