go-json-experiment / json

Experimental implementation of a proposed v2 encoding/json package
BSD 3-Clause "New" or "Revised" License
341 stars 11 forks source link

naming: add field naming conventions #5

Closed tonybase closed 9 months ago

tonybase commented 2 years ago

Added MarshalOptions to control naming conventions. eg: snake_case, camelCase or PascalCase

func FieldCamelCase(tag Tag) string {
    // TODO: proto name
    return tag.Name
}
json.MarshalOptions{
    FieldNaming: FieldCamelCase,
}
dsnet commented 2 years ago

A Turing-complete function callback is going to be non-performance since it makes it impossible to pre-compute and cache the set of alternative names. In practice, there's only a small set of alternative naming conventions (e.g., snake_case, camelCase, PascalCase, kebab-case, etc.) that users would want.

Setting aside the performance aspects, it's difficult to have an automatic naming-convention converter that works well for all cases. In my work on protobufs, I saw several cases where the automatic camel-casing functionality of protobuf led to problems. It seems that it's better to require users be explicit about the JSON names than to do something automatic that had poor failure modes.

Related issues:

bjg2 commented 2 years ago

@dsnet I don't understand why / how it is better to name each and every field with a tag than to have name generator fn + to override it with tag if there is ever need for doing so?

@tonybase I don't understand, your FieldNaming function takes only tag as an argument, not field name? That defies our usecase, to have correct name generated withiut tag?

In Videobolt, we have every public field json name tagged with generator code which we run in our devops. We have hundreds of fields json tagged. We do this just to lowercase first letter (it is always uppercased in field names in go, for a field to be public, and we think that upper cammel case in json is bad, especially in the API). We would like to avoid all of this by just having a choice to always use lower cammel case (if not overriden in tag), or with function that builds name from field name (if not overriden by tag, or builds name from field name + tag).

dsnet commented 9 months ago

Closing this as out-of-scope. This can always be a proposal over at github.com/golang/go.

In general, a Turing-complete rename function will not be performant as it interferes with caching. Automatic casing at marshal/unmarshal time is problematic and my experience with it in protobuf is that it's a bad idea.

That said, a static analysis tool that automatically injects the casing for you sounds reasonable as the casing result would be upfront in your code-editor and you can decide whether it is correct or not. If so, that is still out-of-scope for this project.

dsnet commented 9 months ago

Also, the set of features added to the module are inspired by the most popular requests on the main issue tracker: https://github.com/golang/go/issues?q=is%3Aissue+is%3Aopen+encoding%2Fjson+in%3Atitle+sort%3Areactions-%2B1-desc+

There isn't a popular issue that backs a request like this.