package jsonpb
import (
protoV2
)
const wrapJSONMarshalV2 = false
type Marshaler struct {
OrigName bool
EnumsAsInts bool
EmitDefaults bool
Indent string
AnyResolver AnyResolver
}
type JSONPBMarshaler interface {
MarshalJSONPB(*Marshaler) ([]byte, error)
}
func ( *Marshaler) ( io.Writer, proto.Message) error {
, := .marshal()
if len() > 0 {
if , := .Write(); != nil {
return
}
}
return
}
func ( *Marshaler) ( proto.Message) (string, error) {
, := .marshal()
if != nil {
return "",
}
return string(), nil
}
func ( *Marshaler) ( proto.Message) ([]byte, error) {
:= reflect.ValueOf()
if == nil || (.Kind() == reflect.Ptr && .IsNil()) {
return nil, errors.New("Marshal called with nil")
}
if , := .(JSONPBMarshaler); {
return .MarshalJSONPB()
}
if wrapJSONMarshalV2 {
:= protojson.MarshalOptions{
UseProtoNames: .OrigName,
UseEnumNumbers: .EnumsAsInts,
EmitUnpopulated: .EmitDefaults,
Indent: .Indent,
}
if .AnyResolver != nil {
.Resolver = anyResolver{.AnyResolver}
}
return .Marshal(proto.MessageReflect().Interface())
} else {
:= proto.MessageReflect()
if := protoV2.CheckInitialized(.Interface()); != nil {
return nil,
}
:= jsonWriter{Marshaler: }
:= .marshalMessage(, "", "")
return .buf,
}
}
type jsonWriter struct {
*Marshaler
buf []byte
}
func ( *jsonWriter) ( string) {
.buf = append(.buf, ...)
}
func ( *jsonWriter) ( protoreflect.Message, , string) error {
if , := proto.MessageV1(.Interface()).(JSONPBMarshaler); {
, := .MarshalJSONPB(.Marshaler)
if != nil {
return
}
if != "" {
var map[string]*json.RawMessage
if = json.Unmarshal(, &); != nil {
return fmt.Errorf("type %T produced invalid JSON: %v", .Interface(), )
}
, := json.Marshal()
if != nil {
return fmt.Errorf("failed to marshal type URL %q to JSON: %v", , )
}
["@type"] = (*json.RawMessage)(&)
if , = json.Marshal(); != nil {
return
}
}
.write(string())
return nil
}
:= .Descriptor()
:= .Fields()
const = int64(time.Second / time.Nanosecond)
switch wellKnownType(.FullName()) {
case "Any":
return .marshalAny(, )
case "BoolValue", "BytesValue", "StringValue",
"Int32Value", "UInt32Value", "FloatValue",
"Int64Value", "UInt64Value", "DoubleValue":
:= .ByNumber(1)
return .marshalValue(, .Get(), )
case "Duration":
const = 315576000000
:= .Get(.ByNumber(1)).Int()
:= .Get(.ByNumber(2)).Int()
if < - || > {
return fmt.Errorf("seconds out of range %v", )
}
if <= - || >= {
return fmt.Errorf("ns out of range (%v, %v)", -, )
}
if ( > 0 && < 0) || ( < 0 && > 0) {
return errors.New("signs of seconds and nanos do not match")
}
var string
if < 0 || < 0 {
, , = "-", -1*, -1*
}
:= fmt.Sprintf("%s%d.%09d", , , )
= strings.TrimSuffix(, "000")
= strings.TrimSuffix(, "000")
= strings.TrimSuffix(, ".000")
.write(fmt.Sprintf(`"%vs"`, ))
return nil
case "Timestamp":
:= .Get(.ByNumber(1)).Int()
:= .Get(.ByNumber(2)).Int()
if < 0 || >= {
return fmt.Errorf("ns out of range [0, %v)", )
}
:= time.Unix(, ).UTC()
:= .Format("2006-01-02T15:04:05.000000000")
= strings.TrimSuffix(, "000")
= strings.TrimSuffix(, "000")
= strings.TrimSuffix(, ".000")
.write(fmt.Sprintf(`"%vZ"`, ))
return nil
case "Value":
:= .Oneofs().Get(0)
:= .WhichOneof()
if == nil {
return errors.New("nil Value")
}
return .marshalValue(, .Get(), )
case "Struct", "ListValue":
:= .ByNumber(1)
return .marshalValue(, .Get(), )
}
.write("{")
if .Indent != "" {
.write("\n")
}
:= true
if != "" {
if := .marshalTypeURL(, ); != nil {
return
}
= false
}
for := 0; < .Len(); {
:= .Get()
if := .ContainingOneof(); != nil {
= .WhichOneof()
+= .Fields().Len()
if == nil {
continue
}
} else {
++
}
:= .Get()
if !.Has() {
if !.EmitDefaults || .ContainingOneof() != nil {
continue
}
if .Cardinality() != protoreflect.Repeated && (.Message() != nil || .Syntax() == protoreflect.Proto2) {
= protoreflect.Value{}
}
}
if ! {
.writeComma()
}
if := .marshalField(, , ); != nil {
return
}
= false
}
if .ExtensionRanges().Len() > 0 {
type struct {
protoreflect.FieldDescriptor
protoreflect.Value
}
var []
.Range(func( protoreflect.FieldDescriptor, protoreflect.Value) bool {
if .IsExtension() {
= append(, {, })
}
return true
})
sort.Slice(, func(, int) bool {
return []..Number() < []..Number()
})
for , := range {
if ! {
.writeComma()
}
if := .marshalField(., ., ); != nil {
return
}
= false
}
}
if .Indent != "" {
.write("\n")
.write()
}
.write("}")
return nil
}
func ( *jsonWriter) () {
if .Indent != "" {
.write(",\n")
} else {
.write(",")
}
}
func ( *jsonWriter) ( protoreflect.Message, string) error {
:= .Descriptor()
:= .Get(.Fields().ByNumber(1)).String()
:= .Get(.Fields().ByNumber(2)).Bytes()
var protoreflect.Message
if .AnyResolver != nil {
, := .AnyResolver.Resolve()
if != nil {
return
}
= proto.MessageReflect()
} else {
, := protoregistry.GlobalTypes.FindMessageByURL()
if != nil {
return
}
= .New()
}
if := protoV2.Unmarshal(, .Interface()); != nil {
return
}
if wellKnownType(.Descriptor().FullName()) == "" {
return .marshalMessage(, , )
}
.write("{")
if .Indent != "" {
.write("\n")
}
if := .marshalTypeURL(, ); != nil {
return
}
.writeComma()
if .Indent != "" {
.write()
.write(.Indent)
.write(`"value": `)
} else {
.write(`"value":`)
}
if := .marshalMessage(, +.Indent, ""); != nil {
return
}
if .Indent != "" {
.write("\n")
.write()
}
.write("}")
return nil
}
func ( *jsonWriter) (, string) error {
if .Indent != "" {
.write()
.write(.Indent)
}
.write(`"@type":`)
if .Indent != "" {
.write(" ")
}
, := json.Marshal()
if != nil {
return
}
.write(string())
return nil
}
func ( *jsonWriter) ( protoreflect.FieldDescriptor, protoreflect.Value, string) error {
if .Indent != "" {
.write()
.write(.Indent)
}
.write(`"`)
switch {
case .IsExtension():
:= string(.FullName())
if isMessageSet(.ContainingMessage()) {
= strings.TrimSuffix(, ".message_set_extension")
}
.write("[" + + "]")
case .OrigName:
:= string(.Name())
if .Kind() == protoreflect.GroupKind {
= string(.Message().Name())
}
.write()
default:
.write(string(.JSONName()))
}
.write(`":`)
if .Indent != "" {
.write(" ")
}
return .marshalValue(, , )
}
func ( *jsonWriter) ( protoreflect.FieldDescriptor, protoreflect.Value, string) error {
switch {
case .IsList():
.write("[")
:= ""
:= .List()
for := 0; < .Len(); ++ {
.write()
if .Indent != "" {
.write("\n")
.write()
.write(.Indent)
.write(.Indent)
}
if := .marshalSingularValue(, .Get(), +.Indent); != nil {
return
}
= ","
}
if .Indent != "" {
.write("\n")
.write()
.write(.Indent)
}
.write("]")
return nil
case .IsMap():
:= .MapKey()
:= .MapValue()
:= .Map()
type struct{ , protoreflect.Value }
var []
.Range(func( protoreflect.MapKey, protoreflect.Value) bool {
= append(, {.Value(), })
return true
})
sort.Slice(, func(, int) bool {
switch .Kind() {
case protoreflect.BoolKind:
return ![]..Bool() && []..Bool()
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind, protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
return []..Int() < []..Int()
case protoreflect.Uint32Kind, protoreflect.Fixed32Kind, protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
return []..Uint() < []..Uint()
case protoreflect.StringKind:
return []..String() < []..String()
default:
panic("invalid kind")
}
})
.write(`{`)
:= ""
for , := range {
.write()
if .Indent != "" {
.write("\n")
.write()
.write(.Indent)
.write(.Indent)
}
:= fmt.Sprint(..Interface())
, := json.Marshal()
if != nil {
return
}
.write(string())
.write(`:`)
if .Indent != "" {
.write(` `)
}
if := .marshalSingularValue(, ., +.Indent); != nil {
return
}
= ","
}
if .Indent != "" {
.write("\n")
.write()
.write(.Indent)
}
.write(`}`)
return nil
default:
return .marshalSingularValue(, , )
}
}
func ( *jsonWriter) ( protoreflect.FieldDescriptor, protoreflect.Value, string) error {
switch {
case !.IsValid():
.write("null")
return nil
case .Message() != nil:
return .marshalMessage(.Message(), +.Indent, "")
case .Enum() != nil:
if .Enum().FullName() == "google.protobuf.NullValue" {
.write("null")
return nil
}
:= .Enum().Values().ByNumber(.Enum())
if == nil || .EnumsAsInts {
.write(strconv.Itoa(int(.Enum())))
} else {
.write(`"` + string(.Name()) + `"`)
}
return nil
default:
switch .Interface().(type) {
case float32, float64:
switch {
case math.IsInf(.Float(), +1):
.write(`"Infinity"`)
return nil
case math.IsInf(.Float(), -1):
.write(`"-Infinity"`)
return nil
case math.IsNaN(.Float()):
.write(`"NaN"`)
return nil
}
case int64, uint64:
.write(fmt.Sprintf(`"%d"`, .Interface()))
return nil
}
, := json.Marshal(.Interface())
if != nil {
return
}
.write(string())
return nil
}
}