github.com/DoNewsCode/core@v0.12.3/codec/json/json.go (about) 1 // Package json provides the json codec. 2 // 3 // The code and tests in this package is derived from 4 // https://github.com/go-kratos/kratos under MIT license 5 // https://github.com/go-kratos/kratos/blob/main/LICENSE 6 package json 7 8 import ( 9 "encoding/json" 10 "reflect" 11 12 "google.golang.org/protobuf/encoding/protojson" 13 "google.golang.org/protobuf/proto" 14 ) 15 16 // Codec is a Codec implementation with json. 17 type Codec struct { 18 prefix string 19 indent string 20 marshalOptions protojson.MarshalOptions 21 unmarshalOptions protojson.UnmarshalOptions 22 } 23 24 // Option is the type of functional options to codec 25 type Option func(*Codec) 26 27 // NewCodec creates a new json codec 28 func NewCodec(opts ...Option) Codec { 29 var ( 30 codec Codec 31 marshalOptions = protojson.MarshalOptions{ 32 EmitUnpopulated: true, 33 } 34 unmarshalOptions = protojson.UnmarshalOptions{ 35 DiscardUnknown: true, 36 } 37 ) 38 codec.marshalOptions = marshalOptions 39 codec.unmarshalOptions = unmarshalOptions 40 for _, f := range opts { 41 f(&codec) 42 } 43 return codec 44 } 45 46 // WithIndent allows the codec to indent json output while marshalling. It is 47 // useful when the json output is meant for humans to read. 48 func WithIndent(indent string) Option { 49 return func(codec *Codec) { 50 codec.indent = indent 51 codec.marshalOptions.Multiline = true 52 codec.marshalOptions.Indent = indent 53 } 54 } 55 56 // Marshal serialize the interface{} to []byte 57 func (c Codec) Marshal(v interface{}) ([]byte, error) { 58 if m, ok := v.(proto.Message); ok { 59 return c.marshalOptions.Marshal(m) 60 } 61 if c.indent != "" { 62 return json.MarshalIndent(v, c.prefix, c.indent) 63 } 64 return json.Marshal(v) 65 } 66 67 // Unmarshal deserialize the []byte to interface{} 68 func (c Codec) Unmarshal(data []byte, v interface{}) error { 69 rv := reflect.ValueOf(v) 70 for rv.Kind() == reflect.Ptr { 71 if rv.IsNil() { 72 rv.Set(reflect.New(rv.Type().Elem())) 73 } 74 rv = rv.Elem() 75 } 76 if m, ok := v.(proto.Message); ok { 77 return c.unmarshalOptions.Unmarshal(data, m) 78 } else if m, ok := reflect.Indirect(reflect.ValueOf(v)).Interface().(proto.Message); ok { 79 return c.unmarshalOptions.Unmarshal(data, m) 80 } 81 return json.Unmarshal(data, v) 82 }