Reputation: 93
I have a protobuf message
message Event {
string type = 1;
string names = 2;
}
The type for ‘names’ has recently changed from string
to []string
in the underlying data source where older data is still a string but new data is going to be []string.
So, when the data is returned, some records can have string and the rest can have []string.
I need to customize the unmarshaling (jsonpb.Unmarshaler is being used to unmarshal json.Rawmessage to Event type) and convert the ‘names’ to a string if it’s an []string (by concatenating the values from array/slice) in order to keep the response format consistent so client doesn't break.
I get this error while unmarshaling:
json: cannot unmarshal array into Go value of type string
Can anyone please suggest on how this can be done?
I tried google.protobuf.Any like below but couldn’t completely figure the unmarshaling part.
message Event {
string type = 1;
google.protobuf.Any names = 2;
}
Unmarshall snippet:
evnt := new(pb.Event)
unmarshaler = jsonpb.Unmarshaler{AllowUnknownFields: true}
unmarshaler.Unmarshal(bytes.NewReader(*<json.RawMessage>*), evnt)
Upvotes: 1
Views: 5122
Reputation: 312
Make the name into a type then give it a custom UnmarshalJSON
method. Example:
package main
import (
"encoding/json"
"fmt"
"os"
"strings"
)
type name struct {
New []string
Old string
}
type event struct {
Type string `json:"type"`
Name name `json:"name"`
}
func do(j string) {
var e event
err := json.Unmarshal([]byte(j), &e)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to unmarshall %s: %s\n", j, err)
return
}
fmt.Printf("%v\n", e)
}
func (n *name) UnmarshalJSON(text []byte) error {
t := strings.TrimSpace(string(text))
if strings.HasPrefix(t, "[") {
return json.Unmarshal(text, &n.New)
}
return json.Unmarshal(text, &n.Old)
}
func main() {
jsonstring := `{"type":"a","name":"rodney"}`
jsonarray := `{"type":"a","name":["rodney","dangerfield"]}`
do(jsonstring)
do(jsonarray)
}
Playground: https://go.dev/play/p/sNtUZKHC_Rt
Upvotes: 1