diff --git a/bootstrap/bootstrap.go b/bootstrap/bootstrap.go index 231cb92..8236267 100644 --- a/bootstrap/bootstrap.go +++ b/bootstrap/bootstrap.go @@ -20,8 +20,9 @@ type Generator struct { PkgPath, PkgName string Types []string - SnakeCase bool - OmitEmpty bool + NoStdMarshalers bool + SnakeCase bool + OmitEmpty bool OutName string BuildTags string @@ -78,6 +79,9 @@ func (g *Generator) writeMain() (path string, err error) { if g.OmitEmpty { fmt.Fprintln(f, " g.OmitEmpty()") } + if g.NoStdMarshalers { + fmt.Fprintln(f, " g.NoStdMarshalers()") + } for _, v := range g.Types { fmt.Fprintln(f, " g.Add(pkg."+v+"{})") } diff --git a/easyjson/main.go b/easyjson/main.go index c13316c..eace333 100644 --- a/easyjson/main.go +++ b/easyjson/main.go @@ -12,6 +12,7 @@ import ( var buildTags = flag.String("build_tags", "", "build tags to add to generated file") var snakeCase = flag.Bool("snake_case", false, "use snake_case names instead of CamelCase by default") +var noStdMarshalers = flag.Bool("no_std_marshalers", false, "don't generate MarshalJSON/UnmarshalJSON methods") var omitEmpty = flag.Bool("omit_empty", false, "omit empty fields by default") var allStructs = flag.Bool("all", false, "generate un-/marshallers for all structs in a file") var leaveTemps = flag.Bool("leave_temps", false, "do not delete temporary files") @@ -31,15 +32,16 @@ func generate(fname string) (err error) { } g := bootstrap.Generator{ - BuildTags: *buildTags, - PkgPath: p.PkgPath, - PkgName: p.PkgName, - Types: p.StructNames, - SnakeCase: *snakeCase, - OmitEmpty: *omitEmpty, - LeaveTemps: *leaveTemps, - OutName: outName, - StubsOnly: *stubs, + BuildTags: *buildTags, + PkgPath: p.PkgPath, + PkgName: p.PkgName, + Types: p.StructNames, + SnakeCase: *snakeCase, + NoStdMarshalers: *noStdMarshalers, + OmitEmpty: *omitEmpty, + LeaveTemps: *leaveTemps, + OutName: outName, + StubsOnly: *stubs, } if err := g.Run(); err != nil { diff --git a/gen/decoder.go b/gen/decoder.go index eae6009..14fea99 100644 --- a/gen/decoder.go +++ b/gen/decoder.go @@ -1,6 +1,7 @@ package gen import ( + "encoding/json" "fmt" "reflect" "strings" @@ -42,6 +43,14 @@ func (g *Generator) genTypeDecoder(t reflect.Type, out string, indent int) error return nil } + unmarshalerIface = reflect.TypeOf((*json.Unmarshaler)(nil)).Elem() + if reflect.PtrTo(t).Implements(unmarshalerIface) { + fmt.Fprintln(g.out, ws+"if data := in.Raw(); in.Ok() {") + fmt.Fprintln(g.out, ws+" in.AddError( ("+out+").UnmarshalJSON(data) )") + fmt.Fprintln(g.out, ws+"}") + return nil + } + // Check whether type is primitive, needs to be done after interface check. if dec := primitiveDecoders[t.Kind()]; dec != "" { fmt.Fprintln(g.out, ws+out+" = "+dec) @@ -224,11 +233,14 @@ func (g *Generator) genStructUnmarshaller(t reflect.Type) error { fname := g.getStructDecoderName(t) typ := g.getType(t) - fmt.Fprintln(g.out, "func (v *"+typ+") UnmarshalJSON(data []byte) error {") - fmt.Fprintln(g.out, " r := jlexer.Lexer{Data: data}") - fmt.Fprintln(g.out, " "+fname+"(&r, v)") - fmt.Fprintln(g.out, " return r.Error()") - fmt.Fprintln(g.out, "}") + if !g.noStdMarshalers { + fmt.Fprintln(g.out, "func (v *"+typ+") UnmarshalJSON(data []byte) error {") + fmt.Fprintln(g.out, " r := jlexer.Lexer{Data: data}") + fmt.Fprintln(g.out, " "+fname+"(&r, v)") + fmt.Fprintln(g.out, " return r.Error()") + fmt.Fprintln(g.out, "}") + } + fmt.Fprintln(g.out, "func (v *"+typ+") UnmarshalEasyJSON(l *jlexer.Lexer) {") fmt.Fprintln(g.out, " "+fname+"(l, v)") fmt.Fprintln(g.out, "}") diff --git a/gen/encoder.go b/gen/encoder.go index 43ced37..6bc1e51 100644 --- a/gen/encoder.go +++ b/gen/encoder.go @@ -1,6 +1,7 @@ package gen import ( + "encoding/json" "fmt" "reflect" "strconv" @@ -39,6 +40,12 @@ func (g *Generator) genTypeEncoder(t reflect.Type, in string, indent int) error return nil } + marshalerIface = reflect.TypeOf((*json.Marshaler)(nil)).Elem() + if reflect.PtrTo(t).Implements(marshalerIface) { + fmt.Fprintln(g.out, ws+"out.Raw( ("+in+").MarshalJSON() )") + return nil + } + // Check whether type is primitive, needs to be done after interface check. if enc := primitiveEncoders[t.Kind()]; enc != "" { fmt.Fprintln(g.out, ws+enc+"("+in+")") @@ -198,11 +205,13 @@ func (g *Generator) genStructMarshaller(t reflect.Type) error { fname := g.getStructEncoderName(t) typ := g.getType(t) - fmt.Fprintln(g.out, "func (v *"+typ+") MarshalJSON() ([]byte, error) {") - fmt.Fprintln(g.out, " w := jwriter.Writer{}") - fmt.Fprintln(g.out, " "+fname+"(&w, v)") - fmt.Fprintln(g.out, " return w.Buffer.BuildBytes(), w.Error") - fmt.Fprintln(g.out, "}") + if !g.noStdMarshalers { + fmt.Fprintln(g.out, "func (v *"+typ+") MarshalJSON() ([]byte, error) {") + fmt.Fprintln(g.out, " w := jwriter.Writer{}") + fmt.Fprintln(g.out, " "+fname+"(&w, v)") + fmt.Fprintln(g.out, " return w.Buffer.BuildBytes(), w.Error") + fmt.Fprintln(g.out, "}") + } fmt.Fprintln(g.out, "func (v *"+typ+") MarshalEasyJSON(w *jwriter.Writer) {") fmt.Fprintln(g.out, " "+fname+"(w, v)") diff --git a/gen/generator.go b/gen/generator.go index 3b56f35..259014d 100644 --- a/gen/generator.go +++ b/gen/generator.go @@ -29,8 +29,9 @@ type Generator struct { varCounter int - omitEmpty bool - namer FieldNamer + noStdMarshalers bool + omitEmpty bool + namer FieldNamer // package path to local alias map for tracking imports imports map[string]string @@ -85,6 +86,12 @@ func (g *Generator) UseSnakeCase() { g.namer = SnakeCaseFieldNamer{} } +// NoStdMarshalers instructs not to generate standard MarshalJSON/UnmarshalJSON +// methods (only the custom interface). +func (g *Generator) NoStdMarshalers() { + g.noStdMarshalers = true +} + // OmitEmpty triggers `json=",omitempty"` behaviour by default. func (g *Generator) OmitEmpty() { g.omitEmpty = true diff --git a/tests/basic_test.go b/tests/basic_test.go index 9c97614..fc08b3b 100644 --- a/tests/basic_test.go +++ b/tests/basic_test.go @@ -23,6 +23,7 @@ var testCases = []struct { {&omitEmptyDefaultValue, omitEmptyDefaultString}, {&optsValue, optsString}, {&rawValue, rawString}, + {&stdMarshalerValue, stdMarshalerString}, } func TestMarshal(t *testing.T) { diff --git a/tests/data.go b/tests/data.go index 806e4e3..7179b2f 100644 --- a/tests/data.go +++ b/tests/data.go @@ -3,6 +3,7 @@ package tests import ( "fmt" "math" + "time" "github.com/mailru/easyjson" "github.com/mailru/easyjson/opt" @@ -200,3 +201,10 @@ var rawString = `{` + `"Field":{"a" : "b"},` + `"Field2":"test"` + `}` + +type StdMarshaler struct { + T time.Time +} + +var stdMarshalerValue = StdMarshaler{T: time.Date(2016, 01, 02, 14, 15, 10, 0, time.UTC)} +var stdMarshalerString = `{"T":"2016-01-02T14:15:10Z"}`