mirror of
https://github.com/netbirdio/easyjson.git
synced 2026-05-22 18:44:42 -07:00
add interfaces to provide marshal/unmarshal logic for unknown fields in struct
This commit is contained in:
@@ -19,6 +19,7 @@ generate: build
|
||||
./tests/embedded_type.go \
|
||||
./tests/reference_to_pointer.go \
|
||||
./tests/html.go \
|
||||
./tests/unknown_fields.go \
|
||||
|
||||
bin/easyjson -all ./tests/data.go
|
||||
bin/easyjson -all ./tests/nothing.go
|
||||
@@ -34,6 +35,7 @@ generate: build
|
||||
bin/easyjson ./tests/reference_to_pointer.go
|
||||
bin/easyjson ./tests/key_marshaler_map.go
|
||||
bin/easyjson -disallow_unknown_fields ./tests/disallow_unknown.go
|
||||
bin/easyjson ./tests/unknown_fields.go
|
||||
|
||||
test: generate
|
||||
go test \
|
||||
|
||||
@@ -94,6 +94,16 @@ func hasCustomUnmarshaler(t reflect.Type) bool {
|
||||
t.Implements(reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem())
|
||||
}
|
||||
|
||||
func hasUnknownsUnmarshaler(t reflect.Type) bool {
|
||||
t = reflect.PtrTo(t)
|
||||
return t.Implements(reflect.TypeOf((*easyjson.UnknownsUnmarshaler)(nil)).Elem())
|
||||
}
|
||||
|
||||
func hasUnknownsMarshaler(t reflect.Type) bool {
|
||||
t = reflect.PtrTo(t)
|
||||
return t.Implements(reflect.TypeOf((*easyjson.UnknownsMarshaler)(nil)).Elem())
|
||||
}
|
||||
|
||||
// genTypeDecoderNoCheck generates decoding code for the type t.
|
||||
func (g *Generator) genTypeDecoderNoCheck(t reflect.Type, out string, tags fieldTags, indent int) error {
|
||||
ws := strings.Repeat(" ", indent)
|
||||
@@ -485,6 +495,8 @@ func (g *Generator) genStructDecoder(t reflect.Type) error {
|
||||
Reason: "unknown field",
|
||||
Data: key,
|
||||
})`)
|
||||
} else if hasUnknownsUnmarshaler(t) {
|
||||
fmt.Fprintln(g.out, " out.UnmarshalUnknown(in, key)")
|
||||
} else {
|
||||
fmt.Fprintln(g.out, " in.SkipRecursive()")
|
||||
}
|
||||
|
||||
@@ -393,6 +393,14 @@ func (g *Generator) genStructEncoder(t reflect.Type) error {
|
||||
}
|
||||
}
|
||||
|
||||
if hasUnknownsMarshaler(t) {
|
||||
if !firstCondition {
|
||||
fmt.Fprintln(g.out, " in.MarshalUnknowns(out, false)")
|
||||
} else {
|
||||
fmt.Fprintln(g.out, " in.MarshalUnknowns(out, first)")
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Fprintln(g.out, " out.RawByte('}')")
|
||||
fmt.Fprintln(g.out, "}")
|
||||
|
||||
|
||||
+10
@@ -26,6 +26,16 @@ type Optional interface {
|
||||
IsDefined() bool
|
||||
}
|
||||
|
||||
// UnknownsUnmarshaler provides a method to unmarshal unknown struct fileds and save them as you want
|
||||
type UnknownsUnmarshaler interface {
|
||||
UnmarshalUnknown(in *jlexer.Lexer, key string)
|
||||
}
|
||||
|
||||
// UnknownsMarshaler provides a method to write additional struct fields
|
||||
type UnknownsMarshaler interface {
|
||||
MarshalUnknowns(w *jwriter.Writer, first bool)
|
||||
}
|
||||
|
||||
// Marshal returns data as a single byte slice. Method is suboptimal as the data is likely to be copied
|
||||
// from a chain of smaller chunks.
|
||||
func Marshal(v Marshaler) ([]byte, error) {
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package tests
|
||||
|
||||
import "github.com/mailru/easyjson"
|
||||
|
||||
//easyjson:json
|
||||
type StructWithUnknownsProxy struct {
|
||||
easyjson.UnknownFieldsProxy
|
||||
|
||||
Field1 string
|
||||
}
|
||||
|
||||
//easyjson:json
|
||||
type StructWithUnknownsProxyWithOmitempty struct {
|
||||
easyjson.UnknownFieldsProxy
|
||||
|
||||
Field1 string `json:",omitempty"`
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestUnknownFieldsProxy(t *testing.T) {
|
||||
baseJson := `{"Field1":"123","Field2":"321"}`
|
||||
|
||||
s := StructWithUnknownsProxy{}
|
||||
|
||||
err := s.UnmarshalJSON([]byte(baseJson))
|
||||
if err != nil {
|
||||
t.Errorf("UnmarshalJSON didn't expect error: %v", err)
|
||||
}
|
||||
|
||||
if s.Field1 != "123" {
|
||||
t.Errorf("UnmarshalJSON expected to parse Field1 as \"123\". got: %v", s.Field1)
|
||||
}
|
||||
|
||||
data, err := s.MarshalJSON()
|
||||
if err != nil {
|
||||
t.Errorf("MarshalJSON didn't expect error: %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(baseJson, string(data)) {
|
||||
t.Errorf("MarshalJSON expected to gen: %v. got: %v", baseJson, string(data))
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnknownFieldsProxyWithOmitempty(t *testing.T) {
|
||||
baseJson := `{"Field1":"123","Field2":"321"}`
|
||||
|
||||
s := StructWithUnknownsProxyWithOmitempty{}
|
||||
|
||||
err := s.UnmarshalJSON([]byte(baseJson))
|
||||
if err != nil {
|
||||
t.Errorf("UnmarshalJSON didn't expect error: %v", err)
|
||||
}
|
||||
|
||||
if s.Field1 != "123" {
|
||||
t.Errorf("UnmarshalJSON expected to parse Field1 as \"123\". got: %v", s.Field1)
|
||||
}
|
||||
|
||||
data, err := s.MarshalJSON()
|
||||
if err != nil {
|
||||
t.Errorf("MarshalJSON didn't expect error: %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(baseJson, string(data)) {
|
||||
t.Errorf("MarshalJSON expected to gen: %v. got: %v", baseJson, string(data))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package easyjson
|
||||
|
||||
import (
|
||||
json "encoding/json"
|
||||
|
||||
jlexer "github.com/mailru/easyjson/jlexer"
|
||||
"github.com/mailru/easyjson/jwriter"
|
||||
)
|
||||
|
||||
// UnknownFieldsProxy implemets UnknownsUnmarshaler and UnknownsMarshaler
|
||||
// use it as embedded field in your structure to parse and then serialize unknown struct fields
|
||||
type UnknownFieldsProxy struct {
|
||||
unknownFields map[string]interface{}
|
||||
}
|
||||
|
||||
func (s *UnknownFieldsProxy) UnmarshalUnknown(in *jlexer.Lexer, key string) {
|
||||
if s.unknownFields == nil {
|
||||
s.unknownFields = make(map[string]interface{}, 1)
|
||||
}
|
||||
s.unknownFields[key] = in.Interface()
|
||||
}
|
||||
|
||||
func (s UnknownFieldsProxy) MarshalUnknowns(out *jwriter.Writer, first bool) {
|
||||
for key, val := range s.unknownFields {
|
||||
if first {
|
||||
first = false
|
||||
} else {
|
||||
out.RawByte(',')
|
||||
}
|
||||
out.String(string(key))
|
||||
out.RawByte(':')
|
||||
out.Raw(json.Marshal(val))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user