1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
|
package main
import (
"text/template"
pgsgo "github.com/lyft/protoc-gen-star/v2/lang/go"
pgs "github.com/lyft/protoc-gen-star/v2"
)
// JSONifyPlugin adds encoding/json Marshaler and Unmarshaler methods on PB
// messages that utilizes the more correct jsonpb package.
// See: https://godoc.org/github.com/golang/protobuf/jsonpb
type JSONifyModule struct {
*pgs.ModuleBase
ctx pgsgo.Context
tpl *template.Template
}
// JSONify returns an initialized JSONifyPlugin
func JSONify() *JSONifyModule { return &JSONifyModule{ModuleBase: &pgs.ModuleBase{}} }
func (p *JSONifyModule) InitContext(c pgs.BuildContext) {
p.ModuleBase.InitContext(c)
p.ctx = pgsgo.InitContext(c.Parameters())
tpl := template.New("jsonify").Funcs(map[string]interface{}{
"package": p.ctx.PackageName,
"name": p.ctx.Name,
"marshaler": p.marshaler,
"unmarshaler": p.unmarshaler,
})
p.tpl = template.Must(tpl.Parse(jsonifyTpl))
}
// Name satisfies the generator.Plugin interface.
func (p *JSONifyModule) Name() string { return "jsonify" }
func (p *JSONifyModule) Execute(targets map[string]pgs.File, pkgs map[string]pgs.Package) []pgs.Artifact {
for _, t := range targets {
p.generate(t)
}
return p.Artifacts()
}
func (p *JSONifyModule) generate(f pgs.File) {
if len(f.Messages()) == 0 {
return
}
name := p.ctx.OutputPath(f).SetExt(".json.go")
p.AddGeneratorTemplateFile(name.String(), p.tpl, f)
}
func (p *JSONifyModule) marshaler(m pgs.Message) pgs.Name {
return p.ctx.Name(m) + "JSONMarshaler"
}
func (p *JSONifyModule) unmarshaler(m pgs.Message) pgs.Name {
return p.ctx.Name(m) + "JSONUnmarshaler"
}
const jsonifyTpl = `package {{ package . }}
import (
"bytes"
"encoding/json"
"github.com/golang/protobuf/jsonpb"
)
{{ range .AllMessages }}
// {{ marshaler . }} describes the default jsonpb.Marshaler used by all
// instances of {{ name . }}. This struct is safe to replace or modify but
// should not be done so concurrently.
var {{ marshaler . }} = new(jsonpb.Marshaler)
// MarshalJSON satisfies the encoding/json Marshaler interface. This method
// uses the more correct jsonpb package to correctly marshal the message.
func (m *{{ name . }}) MarshalJSON() ([]byte, error) {
if m == nil {
return json.Marshal(nil)
}
buf := &bytes.Buffer{}
if err := {{ marshaler . }}.Marshal(buf, m); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
var _ json.Marshaler = (*{{ name . }})(nil)
// {{ unmarshaler . }} describes the default jsonpb.Unmarshaler used by all
// instances of {{ name . }}. This struct is safe to replace or modify but
// should not be done so concurrently.
var {{ unmarshaler . }} = new(jsonpb.Unmarshaler)
// UnmarshalJSON satisfies the encoding/json Unmarshaler interface. This method
// uses the more correct jsonpb package to correctly unmarshal the message.
func (m *{{ name . }}) UnmarshalJSON(b []byte) error {
return {{ unmarshaler . }}.Unmarshal(bytes.NewReader(b), m)
}
var _ json.Unmarshaler = (*{{ name . }})(nil)
{{ end }}
`
|