Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is it possible add default Marshal option to Message.MarshalJSON #378

Closed
SuperGod opened this issue Jan 20, 2021 · 6 comments
Closed

Is it possible add default Marshal option to Message.MarshalJSON #378

SuperGod opened this issue Jan 20, 2021 · 6 comments

Comments

@SuperGod
Copy link

dynamic.Message has two method to marshal json:

  1. MarshalJSON use an empty jsonpb.Marshaler as param to marshal
  2. MarshalJSONPB has a custom jsonpb.Marshaler as param to marshal

json.Marshal function use MarshalJSON to marshal data to json, so user can't change the default json option when use go's encoding/json package,see below code:

msg := dynamic.NewMessage(typ)
data = map[string]interface{}
data["a"] = msg
// user can't change the marshal option of msg
buf,err := json.Marshal(data)

So is it possible add a default Marshal option? like this:

dynamic.DefaultMarshaler = jsonpb.Marshaler{OrigName: true}
msg := dynamic.NewMessage(typ)
data = map[string]interface{}
data["a"] = msg
// use the dynamic.DefaultMarshaler to marshal
buf,err := json.Marshal(data)
@jhump
Copy link
Owner

jhump commented Jan 20, 2021

@SuperGod, I don't intend to add much more (maybe nothing more?) to this package or the desc package because they are now superseded by similar functionality in the new protobuf API in google.golang.org/protobuf. In particular, the google.golang.org/protobuf/reflect/* packages provide similar function as this repo's desc package, and google.golang.org/protobuf/types/dynamicpb can replace this repo's dynamic package.

The only thing I had planned to merge regarding these packages, in fact, is better/easier interop and compatibility with those packages, to make it easier for users to migrate their code to using those other packages. (In fact, I've had a working branch in #354 that I hope to merge soon but want to do a little more performance testing first.)

I would recommend switching to using google.golang.org/protobuf/encoding/protojson instead of encoding/json. This is the only way to get the correct JSON format. I think you may find this to be true for the google.golang.org/protobuf/types/dynamicpb package as well. If you cannot use that package for some reason and must use encoding/json, then I would use a wrapper that provides the serialization you want:

type dynamicMessageWithJSON dynamic.Message

func (m *dynamicMessageWithJSON) MarshalJSON() ([]byte, error) {
    dm := (*dynamic.Message)(m)
    return dm.MarshalJSONPB(&jsonpb.Marshaler{OrigName: true})
}

@SuperGod
Copy link
Author

"type dynamicMessageWithJSON dynamic.Message" maybe useful in some case,but not for me.

My case is like below:

msg := dynamic.NewMessage(typ)
...
data := make(map[string]interface{})
data["a"] = msg.TryGetField(field)
buf,err := json.Marshal(data)
...

"google.golang.org/protobuf/types/dynamicpb" maybe a solution,
but unfortunately "google.golang.org/protobuf/" is incompatible with "github.com/golang/protobuf" v1.3.*

I have to recompile all my proto file when I use "google.golang.org/protobuf/", If there is no other way, I can only do so

@jhump
Copy link
Owner

jhump commented Jan 21, 2021

I don't see why the dynamicMessageWithJSON suggestion wouldn't help you. You'd just wrap any *dynamic.Message value in the map:

msg := dynamic.NewMessage(typ)
// ...
data := make(map[string]interface{})
val := msg.GetField(field)
if dm, ok := val.(*dynamic.Message); ok {
    val = (*dynamicMessageWithJSON)(dm)
}
data["a"] = val
buf,err := json.Marshal(data)
// ...

I have to recompile all my proto file when I use "google.golang.org/protobuf/"

This is not true. The new runtime has an extensive ABI-compatibility layer (which is basically all of "github.com/golang/protobuf" v1.4+). So if you simply upgrade that dependency from 1.3, all of your existing pb.go files will work fine with the newer runtime.

There are some subtle incompatibilities, but the reason the version went from 1.3 to 1.4 (same major version) is because it is intended to be compatible.

@SuperGod
Copy link
Author

I will try your solution.

There is a blog describe "github.com/golang/protobuf" v1.4+ pb.go problem,but in Chinese
https://gocn.vip/topics/10269

The root cause is "github.com/golang/protobuf" v1.4+ Deprecated "InternalMessageInfo",so if you use pb.go generate with v1.3.*, and use v1.4+ package , your code will panic

@jhump
Copy link
Owner

jhump commented Jan 21, 2021

While I don't read Chinese and didn't try to run the whole page through a translator, one thing I did see stood out: it was referring to v1.4.0 (the very first release of the new runtime).

However I believe the issue to which you are referring was fixed in v1.4.2: https://github.com/golang/protobuf/releases/tag/v1.4.2
golang/protobuf#1129

So you might just give it a shot.

@SuperGod
Copy link
Author

Ok,I will try it, thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants