0

I have a structure that looks like this

type MediaFile struct {
    ID                   string    `json:"id"`            
    Secret               string    `json:"-"`
    Title                string    `json:"title"`
}

I want to be able to change the script tag for Secret into json:"secret" when a condition is satisfied.

The struct MediaFile has been referenced a lot within other parts of the code, so using a different Struct with a different name isn't feasible.

I tried to use pointers like follows. Note that I have removed the definition of struct Mediafile as seen before in the following example.

type AlterMediaFile struct {
    ID                   string    `json:"id"`            
    Secret               string    `json:"secret"`
    Title                string    `json:"title"`
}

type MediaFile struct {
    *AlterMediaFile
}

But it resulted in me receiving a lot of promoted field errors since it's AlterMediaFile is basically just a nested class of MediaFile in this case.

So, is there any simple way for me to be able to alter the 'Secret' script tag from json:"-" to json:"secret" ?

BRSwift
  • 57
  • 5
  • 2
    You cannot change struct tags at runtime. You can change the resulting json byte slice, not very nice. You could implement the json.Marshaler interface but the implementation would have to have access to that "condition" based on which it would decide whether to include the secret or not. And you can convert `MediaFile` to `AlterMediaFile` when the condition is met, that's probably the best option. – mkopriva Apr 04 '21 at 05:32
  • Also see: https://stackoverflow.com/questions/42546519/how-do-i-dynamically-change-the-structs-json-tag and https://stackoverflow.com/questions/50748919/changing-json-tags-in-struct-with-custom-marshaljson – mkopriva Apr 04 '21 at 05:36
  • 1
    I see, that's a bummer, but it does make sense. Perhaps, since it's just one struct tag, I might be able to implement a solution based on the function that uses this structure. Thanks for the additional links by the way, I guess I haven't been searching deep enough. – BRSwift Apr 04 '21 at 06:17

2 Answers2

2

You can not alter the 'Secret' script tag from json:"-" to json:"secret" at runtime.

However, you can use the omitempty option, json:"secret,omitempty", to specify that the field should be omitted from the encoding if the field has an empty value (in this case, an empty string).

When your condition is not satisfied, you can just simply set the Secret field to an empty string (this can be done with your database) and it will not show up in the json data.

thks173
  • 1,500
  • 1
  • 8
  • 6
  • This works for me. It seems as though my question was essentially trying to workaround something that didn't need to be worked around. Since I am only trying to change one property, this turned out to be a better solution instead of messing with the structs. Thanks for your help! – BRSwift Apr 04 '21 at 16:22
0

You can write your own MarshalJSON/UnmarshalJSON methods.

type MediaFile struct {
    ID     string
    Secret string
    Title  string
}

type jsonMediaFile struct {
    ID    string `json:"id"`
    Title string `json:"title"`
}

type jsonSecretMediaFile struct {
    *jsonMediaFile
    Secret string `json:"secret"`
}

func (mf *MediaFile) MarshalJSON() ([]byte, error) {
    jsonMF := jsonMediaFile{
        ID:    mf.ID,
        Title: mf.Title,
    }

    if isNeedMarshalSecret() {
        return json.Marshal(jsonSecretMediaFile{
            jsonMediaFile: &jsonMF,
            Secret:        mf.Secret,
        })
    }
    
    return json.Marshal(jsonMF)
}
sirsova
  • 31
  • 1
  • 5
  • Thanks for this solution. I knew Marshalling would probably get my problem fixed. However, it requires the creation of 3 structures which leads to a lot of overhead since this is referenced a lot. Thanks for contributing. – BRSwift Apr 04 '21 at 16:20