You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Currently if a package wants to define a struct that can be saved to and loaded from files in different formats, with field names different from the struct field names (e.g. changing "FooBar" to "foo_bar" to match conventions, "Miscellaneous" to "misc" for brevity, etc), the package must add separate struct tags for json, toml, yaml, etc. Any encoding not specifically enumerated in the tags will either fall back to using the struct field names directly, or have to implement parsing of another encoding's tag. Any tag options supported by multiple encoders must be specified multiple times.
While these different encoding packages offer some unique functionality, such as go-yaml's inline, encoding/json's string, and go-toml's multiline, they all share common functionality of specifying the key name and the omitempty option. Since go-toml v2, they also all use the same structure for the contents of the tag, i.e. "name,option,option...". For use cases where that subset of functionality is sufficient, it would be convenient if most or all of the markup/encoder/serializer/marshaler/etc packages supported a common tag name.
My proposal is for a standard tag that looks and works like the existing tag syntax for toml, json, and yaml, but with a new name. Something like "markup", "marshal", "encoded", "serialized", etc. Preferably relatively short.
With this proposal, and support by the relevant packages, the following code:
This new tag would specify the expected behavior of some options, possibly currently only omitempty, which I believe has consistent behavior across all three of the packages mentioned above, and at least most of the other yaml packages.
Each of the packages could still read its own tag, for both unique and common functionality, with the following proposed conflict resolution behavior:
Specifying a field name in both the new common tag and the package tag would result in the package tag overriding the common tag.
Specifying an option (e.g. omitempty) in the common tag but not the package tag would result in the option still being applied; packages would need to provide an inverse option (e.g. keepempty) in their own tag to override this behavior.
Alternately, packages could read arbitrary options from the standard tag, which would simplify the struct definition even further but risks future collisions between options understood with different meanings by different packages.
The implementation of the functionality to decode this tag could be left to the individual packages, or go in a new part of the standard library possibly somewhere near reflect.StructTag.Get or elsewhere in encoding (possibly the same place that #60770 ends up if we move tagOptions and parseTag out of encoding/json), or may end up in a third party package like https://pkg.go.dev/github.com/fatih/structtag. Wherever it ends up, the conflict resolution described above could also be implemented generically and made available to all consuming packages.
The text was updated successfully, but these errors were encountered:
@Nasfame Regarding collisions, I have used github code search to search for path:*.go StructTag AND "Get(\"json\")" and equivalent for other tag names. The "code" category results are as follows:
@carlmjohnson The developer of go-toml has said he will use this proposal if it succeeds, but will not use the json struct tag in the main release of his package.
ianlancetaylor
changed the title
proposal: encoding/json: Support a generic struct tag for marshaled field name and common options
proposal: encoding/json: support a generic struct tag for marshaled field name and common options
Mar 15, 2024
Currently if a package wants to define a struct that can be saved to and loaded from files in different formats, with field names different from the struct field names (e.g. changing "FooBar" to "foo_bar" to match conventions, "Miscellaneous" to "misc" for brevity, etc), the package must add separate struct tags for json, toml, yaml, etc. Any encoding not specifically enumerated in the tags will either fall back to using the struct field names directly, or have to implement parsing of another encoding's tag. Any tag options supported by multiple encoders must be specified multiple times.
While these different encoding packages offer some unique functionality, such as go-yaml's
inline
, encoding/json'sstring
, and go-toml'smultiline
, they all share common functionality of specifying the key name and theomitempty
option. Since go-toml v2, they also all use the same structure for the contents of the tag, i.e."name,option,option..."
. For use cases where that subset of functionality is sufficient, it would be convenient if most or all of the markup/encoder/serializer/marshaler/etc packages supported a common tag name.My proposal is for a standard tag that looks and works like the existing tag syntax for toml, json, and yaml, but with a new name. Something like "markup", "marshal", "encoded", "serialized", etc. Preferably relatively short.
With this proposal, and support by the relevant packages, the following code:
might be replaced with this:
This new tag would specify the expected behavior of some options, possibly currently only
omitempty
, which I believe has consistent behavior across all three of the packages mentioned above, and at least most of the other yaml packages.Each of the packages could still read its own tag, for both unique and common functionality, with the following proposed conflict resolution behavior:
omitempty
) in the common tag but not the package tag would result in the option still being applied; packages would need to provide an inverse option (e.g.keepempty
) in their own tag to override this behavior.Alternately, packages could read arbitrary options from the standard tag, which would simplify the struct definition even further but risks future collisions between options understood with different meanings by different packages.
The implementation of the functionality to decode this tag could be left to the individual packages, or go in a new part of the standard library possibly somewhere near
reflect.StructTag.Get
or elsewhere inencoding
(possibly the same place that #60770 ends up if we movetagOptions
andparseTag
out ofencoding/json
), or may end up in a third party package like https://pkg.go.dev/github.com/fatih/structtag. Wherever it ends up, the conflict resolution described above could also be implemented generically and made available to all consuming packages.The text was updated successfully, but these errors were encountered: