You've already forked json-iterator
							
							
				mirror of
				https://github.com/json-iterator/go.git
				synced 2025-10-31 00:07:40 +02:00 
			
		
		
		
	#66 Make extension api like the java version
This commit is contained in:
		| @@ -12,7 +12,6 @@ import ( | ||||
| type Config struct { | ||||
| 	IndentionStep                 int | ||||
| 	MarshalFloatWith6Digits       bool | ||||
| 	SupportUnexportedStructFields bool | ||||
| 	EscapeHtml                    bool | ||||
| 	SortMapKeys                   bool | ||||
| 	UseNumber                     bool | ||||
| @@ -24,7 +23,7 @@ type frozenConfig struct { | ||||
| 	indentionStep      int | ||||
| 	decoderCache       unsafe.Pointer | ||||
| 	encoderCache       unsafe.Pointer | ||||
| 	extensions         []ExtensionFunc | ||||
| 	extensions         []Extension | ||||
| 	streamPool         chan *Stream | ||||
| 	iteratorPool       chan *Iterator | ||||
| } | ||||
| @@ -65,9 +64,6 @@ func (cfg Config) Froze() *frozenConfig { | ||||
| 	if cfg.MarshalFloatWith6Digits { | ||||
| 		frozenConfig.marshalFloatWith6Digits() | ||||
| 	} | ||||
| 	if cfg.SupportUnexportedStructFields { | ||||
| 		frozenConfig.supportUnexportedStructFields() | ||||
| 	} | ||||
| 	if cfg.EscapeHtml { | ||||
| 		frozenConfig.escapeHtml() | ||||
| 	} | ||||
| @@ -88,17 +84,10 @@ func (cfg *frozenConfig) useNumber() { | ||||
| 	}}) | ||||
| } | ||||
|  | ||||
| // RegisterExtension can register a custom extension | ||||
| func (cfg *frozenConfig) registerExtension(extension ExtensionFunc) { | ||||
| func (cfg *frozenConfig) registerExtension(extension Extension) { | ||||
| 	cfg.extensions = append(cfg.extensions, extension) | ||||
| } | ||||
|  | ||||
| func (cfg *frozenConfig) supportUnexportedStructFields() { | ||||
| 	cfg.registerExtension(func(type_ reflect.Type, field *reflect.StructField) ([]string, EncoderFunc, DecoderFunc) { | ||||
| 		return []string{field.Name}, nil, nil | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| type lossyFloat32Encoder struct { | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -4,28 +4,54 @@ import ( | ||||
| 	"reflect" | ||||
| 	"fmt" | ||||
| 	"unsafe" | ||||
| 	"strings" | ||||
| 	"unicode" | ||||
| ) | ||||
|  | ||||
| var typeDecoders map[string]ValDecoder | ||||
| var fieldDecoders map[string]ValDecoder | ||||
| var typeEncoders map[string]ValEncoder | ||||
| var fieldEncoders map[string]ValEncoder | ||||
| var extensions []ExtensionFunc | ||||
| var typeDecoders = map[string]ValDecoder{} | ||||
| var fieldDecoders = map[string]ValDecoder{} | ||||
| var typeEncoders = map[string]ValEncoder{} | ||||
| var fieldEncoders = map[string]ValEncoder{} | ||||
| var extensions = []Extension{} | ||||
|  | ||||
| type ExtensionFunc func(typ reflect.Type, field *reflect.StructField) ([]string, EncoderFunc, DecoderFunc) | ||||
| type StructDescriptor struct { | ||||
| 	Type   reflect.Type | ||||
| 	Fields map[string]*Binding | ||||
| } | ||||
|  | ||||
| type Binding struct { | ||||
| 	Field           *reflect.StructField | ||||
| 	FromNames       []string | ||||
| 	ToNames         []string | ||||
| 	ShouldOmitEmpty bool | ||||
| 	Encoder         ValEncoder | ||||
| 	Decoder         ValDecoder | ||||
| } | ||||
|  | ||||
| type Extension interface { | ||||
| 	UpdateStructDescriptor(structDescriptor *StructDescriptor) | ||||
| 	CreateDecoder(typ reflect.Type) ValDecoder | ||||
| 	CreateEncoder(typ reflect.Type) ValEncoder | ||||
| } | ||||
|  | ||||
| type DummyExtension struct { | ||||
| } | ||||
|  | ||||
| func (extension *DummyExtension) UpdateStructDescriptor(structDescriptor *StructDescriptor) { | ||||
| } | ||||
|  | ||||
| func (extension *DummyExtension) CreateDecoder(typ reflect.Type) ValDecoder { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (extension *DummyExtension) CreateEncoder(typ reflect.Type) ValEncoder { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type funcDecoder struct { | ||||
| 	fun DecoderFunc | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	typeDecoders = map[string]ValDecoder{} | ||||
| 	fieldDecoders = map[string]ValDecoder{} | ||||
| 	typeEncoders = map[string]ValEncoder{} | ||||
| 	fieldEncoders = map[string]ValEncoder{} | ||||
| 	extensions = []ExtensionFunc{} | ||||
| } | ||||
|  | ||||
| func RegisterTypeDecoderFunc(typ string, fun DecoderFunc) { | ||||
| 	typeDecoders[typ] = &funcDecoder{fun} | ||||
| } | ||||
| @@ -58,36 +84,134 @@ func RegisterFieldEncoder(typ string, field string, encoder ValEncoder) { | ||||
| 	fieldEncoders[fmt.Sprintf("%s/%s", typ, field)] = encoder | ||||
| } | ||||
|  | ||||
| func RegisterExtension(extension ExtensionFunc) { | ||||
| func RegisterExtension(extension Extension) { | ||||
| 	extensions = append(extensions, extension) | ||||
| } | ||||
|  | ||||
| func getTypeDecoderFromExtension(typ reflect.Type) ValDecoder { | ||||
| 	for _, extension := range extensions { | ||||
| 		decoder := extension.CreateDecoder(typ) | ||||
| 		if decoder != nil { | ||||
| 			return decoder | ||||
| 		} | ||||
| 	} | ||||
| 	typeName := typ.String() | ||||
| 	typeDecoder := typeDecoders[typeName] | ||||
| 	if typeDecoder != nil { | ||||
| 		return typeDecoder | ||||
| 	decoder := typeDecoders[typeName] | ||||
| 	if decoder != nil { | ||||
| 		return decoder | ||||
| 	} | ||||
| 	if typ.Kind() == reflect.Ptr { | ||||
| 		typeDecoder := typeDecoders[typ.Elem().String()] | ||||
| 		if typeDecoder != nil { | ||||
| 			return &optionalDecoder{typ.Elem(), typeDecoder} | ||||
| 		decoder := typeDecoders[typ.Elem().String()] | ||||
| 		if decoder != nil { | ||||
| 			return &optionalDecoder{typ.Elem(), decoder} | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func getTypeEncoderFromExtension(typ reflect.Type) ValEncoder { | ||||
| 	for _, extension := range extensions { | ||||
| 		encoder := extension.CreateEncoder(typ) | ||||
| 		if encoder != nil { | ||||
| 			return encoder | ||||
| 		} | ||||
| 	} | ||||
| 	typeName := typ.String() | ||||
| 	typeEncoder := typeEncoders[typeName] | ||||
| 	if typeEncoder != nil { | ||||
| 		return typeEncoder | ||||
| 	encoder := typeEncoders[typeName] | ||||
| 	if encoder != nil { | ||||
| 		return encoder | ||||
| 	} | ||||
| 	if typ.Kind() == reflect.Ptr { | ||||
| 		typeEncoder := typeEncoders[typ.Elem().String()] | ||||
| 		if typeEncoder != nil { | ||||
| 			return &optionalEncoder{typeEncoder} | ||||
| 		encoder := typeEncoders[typ.Elem().String()] | ||||
| 		if encoder != nil { | ||||
| 			return &optionalEncoder{encoder} | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func describeStruct(cfg *frozenConfig, typ reflect.Type) (*StructDescriptor, error) { | ||||
| 	bindings := map[string]*Binding{} | ||||
| 	for _, field := range listStructFields(typ) { | ||||
| 		tagParts := strings.Split(field.Tag.Get("json"), ",") | ||||
| 		fieldNames := calcFieldNames(field.Name, tagParts[0]) | ||||
| 		fieldCacheKey := fmt.Sprintf("%s/%s", typ.String(), field.Name) | ||||
| 		decoder := fieldDecoders[fieldCacheKey] | ||||
| 		if decoder == nil && len(fieldNames) > 0 { | ||||
| 			var err error | ||||
| 			decoder, err = decoderOfType(cfg, field.Type) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 		} | ||||
| 		encoder := fieldEncoders[fieldCacheKey] | ||||
| 		if encoder == nil && len(fieldNames) > 0 { | ||||
| 			var err error | ||||
| 			encoder, err = encoderOfType(cfg, field.Type) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			// map is stored as pointer in the struct | ||||
| 			if field.Type.Kind() == reflect.Map { | ||||
| 				encoder = &optionalEncoder{encoder} | ||||
| 			} | ||||
| 		} | ||||
| 		binding := &Binding{ | ||||
| 			Field:     field, | ||||
| 			FromNames: fieldNames, | ||||
| 			ToNames:   fieldNames, | ||||
| 			Decoder:   decoder, | ||||
| 			Encoder:   encoder, | ||||
| 		} | ||||
| 		for _, tagPart := range tagParts[1:] { | ||||
| 			if tagPart == "omitempty" { | ||||
| 				binding.ShouldOmitEmpty = true | ||||
| 			} else if tagPart == "string" { | ||||
| 				binding.Decoder = &stringModeDecoder{binding.Decoder} | ||||
| 				binding.Encoder = &stringModeEncoder{binding.Encoder} | ||||
| 			} | ||||
| 		} | ||||
| 		bindings[field.Name] = binding | ||||
| 	} | ||||
| 	structDescriptor := &StructDescriptor{ | ||||
| 		Type:   typ, | ||||
| 		Fields: bindings, | ||||
| 	} | ||||
| 	for _, extension := range extensions { | ||||
| 		extension.UpdateStructDescriptor(structDescriptor) | ||||
| 	} | ||||
| 	return structDescriptor, nil | ||||
| } | ||||
|  | ||||
| func listStructFields(typ reflect.Type) []*reflect.StructField { | ||||
| 	fields := []*reflect.StructField{} | ||||
| 	for i := 0; i < typ.NumField(); i++ { | ||||
| 		field := typ.Field(i) | ||||
| 		if field.Anonymous { | ||||
| 			fields = append(fields, listStructFields(field.Type)...) | ||||
| 		} else { | ||||
| 			fields = append(fields, &field) | ||||
| 		} | ||||
| 	} | ||||
| 	return fields | ||||
| } | ||||
|  | ||||
| func calcFieldNames(originalFieldName string, tagProvidedFieldName string) []string { | ||||
| 	// tag => exported? => original | ||||
| 	isNotExported := unicode.IsLower(rune(originalFieldName[0])) | ||||
| 	var fieldNames []string | ||||
| 	/// tagParts[0] always present, even if no tags | ||||
| 	switch tagProvidedFieldName { | ||||
| 	case "": | ||||
| 		if isNotExported { | ||||
| 			fieldNames = []string{} | ||||
| 		} else { | ||||
| 			fieldNames = []string{originalFieldName} | ||||
| 		} | ||||
| 	case "-": | ||||
| 		fieldNames = []string{} | ||||
| 	default: | ||||
| 		fieldNames = []string{tagProvidedFieldName} | ||||
| 	} | ||||
| 	return fieldNames | ||||
| } | ||||
| @@ -4,64 +4,19 @@ import ( | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"reflect" | ||||
| 	"strings" | ||||
| 	"unicode" | ||||
| 	"unsafe" | ||||
| ) | ||||
|  | ||||
| func encoderOfStruct(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) { | ||||
| 	structEncoder_ := &structEncoder{} | ||||
| 	fields := map[string]*structFieldEncoder{} | ||||
| 	for _, field := range listStructFields(typ) { | ||||
| 		fieldEncoderKey := fmt.Sprintf("%s/%s", typ.String(), field.Name) | ||||
| 		var extensionProvidedFieldNames []string | ||||
| 		for _, extension := range extensions { | ||||
| 			alternativeFieldNames, fun, _ := extension(typ, field) | ||||
| 			if alternativeFieldNames != nil { | ||||
| 				extensionProvidedFieldNames = alternativeFieldNames | ||||
| 			} | ||||
| 			if fun != nil { | ||||
| 				fieldEncoders[fieldEncoderKey] = &funcEncoder{fun, nil} | ||||
| 			} | ||||
| 		} | ||||
| 		for _, extension := range cfg.extensions { | ||||
| 			alternativeFieldNames, fun, _ := extension(typ, field) | ||||
| 			if alternativeFieldNames != nil { | ||||
| 				extensionProvidedFieldNames = alternativeFieldNames | ||||
| 			} | ||||
| 			if fun != nil { | ||||
| 				fieldEncoders[fieldEncoderKey] = &funcEncoder{fun, nil} | ||||
| 			} | ||||
| 		} | ||||
| 		tagParts := strings.Split(field.Tag.Get("json"), ",") | ||||
| 		// if fieldNames set by extension, use theirs, otherwise try tags | ||||
| 		fieldNames := calcFieldNames(field.Name, tagParts[0], extensionProvidedFieldNames) | ||||
| 		omitempty := false | ||||
| 		stringMode := false | ||||
| 		for _, tagPart := range tagParts[1:] { | ||||
| 			if tagPart == "omitempty" { | ||||
| 				omitempty = true | ||||
| 			} else if tagPart == "string" { | ||||
| 				stringMode = true | ||||
| 			} | ||||
| 		} | ||||
| 		encoder := fieldEncoders[fieldEncoderKey] | ||||
| 		var err error | ||||
| 		if encoder == nil && len(fieldNames) > 0 { | ||||
| 			encoder, err = encoderOfType(cfg, field.Type) | ||||
| 	structDescriptor, err := describeStruct(cfg, typ) | ||||
| 	if err != nil { | ||||
| 				return prefix(fmt.Sprintf("{%s}", field.Name)).addToEncoder(encoder, err) | ||||
| 		return nil, err | ||||
| 	} | ||||
| 			// map is stored as pointer in the struct | ||||
| 			if field.Type.Kind() == reflect.Map { | ||||
| 				encoder = &optionalEncoder{encoder} | ||||
| 			} | ||||
| 		} | ||||
| 		if stringMode { | ||||
| 			encoder = &stringModeEncoder{encoder} | ||||
| 		} | ||||
| 		for _, fieldName := range fieldNames { | ||||
| 			fields[fieldName] = &structFieldEncoder{field, fieldName, encoder, omitempty} | ||||
| 	for _, binding := range structDescriptor.Fields { | ||||
| 		for _, fieldName := range binding.ToNames { | ||||
| 			fields[fieldName] = &structFieldEncoder{binding.Field, fieldName, binding.Encoder, binding.ShouldOmitEmpty} | ||||
| 		} | ||||
| 	} | ||||
| 	if len(fields) == 0 { | ||||
| @@ -73,88 +28,20 @@ func encoderOfStruct(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) { | ||||
| 	return structEncoder_, nil | ||||
| } | ||||
|  | ||||
| func listStructFields(typ reflect.Type) []*reflect.StructField { | ||||
| 	fields := []*reflect.StructField{} | ||||
| 	for i := 0; i < typ.NumField(); i++ { | ||||
| 		field := typ.Field(i) | ||||
| 		if field.Anonymous { | ||||
| 			fields = append(fields, listStructFields(field.Type)...) | ||||
| 		} else { | ||||
| 			fields = append(fields, &field) | ||||
| 		} | ||||
| 	} | ||||
| 	return fields | ||||
| } | ||||
|  | ||||
| func decoderOfStruct(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error) { | ||||
| 	fields := map[string]*structFieldDecoder{} | ||||
| 	for _, field := range listStructFields(typ) { | ||||
| 		fieldDecoderKey := fmt.Sprintf("%s/%s", typ.String(), field.Name) | ||||
| 		var extensionProviedFieldNames []string | ||||
| 		for _, extension := range extensions { | ||||
| 			alternativeFieldNames, _, fun := extension(typ, field) | ||||
| 			if alternativeFieldNames != nil { | ||||
| 				extensionProviedFieldNames = alternativeFieldNames | ||||
| 			} | ||||
| 			if fun != nil { | ||||
| 				fieldDecoders[fieldDecoderKey] = &funcDecoder{fun} | ||||
| 			} | ||||
| 		} | ||||
| 		for _, extension := range cfg.extensions { | ||||
| 			alternativeFieldNames, _, fun := extension(typ, field) | ||||
| 			if alternativeFieldNames != nil { | ||||
| 				extensionProviedFieldNames = alternativeFieldNames | ||||
| 			} | ||||
| 			if fun != nil { | ||||
| 				fieldDecoders[fieldDecoderKey] = &funcDecoder{fun} | ||||
| 			} | ||||
| 		} | ||||
| 		decoder := fieldDecoders[fieldDecoderKey] | ||||
| 		tagParts := strings.Split(field.Tag.Get("json"), ",") | ||||
| 		fieldNames := calcFieldNames(field.Name, tagParts[0], extensionProviedFieldNames) | ||||
| 		if decoder == nil && len(fieldNames) > 0 { | ||||
| 			var err error | ||||
| 			decoder, err = decoderOfType(cfg, field.Type) | ||||
| 	structDescriptor, err := describeStruct(cfg, typ) | ||||
| 	if err != nil { | ||||
| 				return prefix(fmt.Sprintf("{%s}", field.Name)).addToDecoder(decoder, err) | ||||
| 		return nil, err | ||||
| 	} | ||||
| 		} | ||||
| 		for _, tagPart := range tagParts[1:] { | ||||
| 			if tagPart == "string" { | ||||
| 				decoder = &stringModeDecoder{decoder} | ||||
| 			} | ||||
| 		} | ||||
| 		for _, fieldName := range fieldNames { | ||||
| 			fields[fieldName] = &structFieldDecoder{field, decoder} | ||||
| 	for _, binding := range structDescriptor.Fields { | ||||
| 		for _, fieldName := range binding.FromNames { | ||||
| 			fields[fieldName] = &structFieldDecoder{binding.Field, binding.Decoder} | ||||
| 		} | ||||
| 	} | ||||
| 	return createStructDecoder(typ, fields) | ||||
| } | ||||
|  | ||||
| func calcFieldNames(originalFieldName string, tagProvidedFieldName string, extensionProvidedFieldNames []string) []string { | ||||
| 	// tag => extension => exported? => original | ||||
| 	isNotExported := unicode.IsLower(rune(originalFieldName[0])) | ||||
| 	var fieldNames []string | ||||
| 	/// tagParts[0] always present, even if no tags | ||||
| 	switch tagProvidedFieldName { | ||||
| 	case "": | ||||
| 		if extensionProvidedFieldNames != nil { | ||||
| 			fieldNames = extensionProvidedFieldNames | ||||
| 		} else { | ||||
| 			if isNotExported { | ||||
| 				fieldNames = []string{} | ||||
| 			} else { | ||||
| 				fieldNames = []string{originalFieldName} | ||||
| 			} | ||||
| 		} | ||||
| 	case "-": | ||||
| 		fieldNames = []string{} | ||||
| 	default: | ||||
| 		fieldNames = []string{tagProvidedFieldName} | ||||
| 	} | ||||
| 	return fieldNames | ||||
| } | ||||
|  | ||||
| func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder) (ValDecoder, error) { | ||||
| 	knownHash := map[int32]struct{}{ | ||||
| 		0: {}, | ||||
|   | ||||
| @@ -3,7 +3,6 @@ package jsoniter | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"github.com/json-iterator/go/require" | ||||
| 	"reflect" | ||||
| 	"strconv" | ||||
| 	"testing" | ||||
| 	"time" | ||||
| @@ -86,22 +85,30 @@ type TestObject1 struct { | ||||
| 	field1 string | ||||
| } | ||||
|  | ||||
| func Test_customize_field_by_extension(t *testing.T) { | ||||
| 	should := require.New(t) | ||||
| 	RegisterExtension(func(type_ reflect.Type, field *reflect.StructField) ([]string, EncoderFunc, DecoderFunc) { | ||||
| 		if type_.String() == "jsoniter.TestObject1" && field.Name == "field1" { | ||||
| 			encode := func(ptr unsafe.Pointer, stream *Stream) { | ||||
| type testExtension struct { | ||||
| 	DummyExtension | ||||
| } | ||||
|  | ||||
| func (extension *testExtension) UpdateStructDescriptor(structDescriptor *StructDescriptor) { | ||||
| 	if structDescriptor.Type.String() != "jsoniter.TestObject1" { | ||||
| 		return | ||||
| 	} | ||||
| 	binding := structDescriptor.Fields["field1"] | ||||
| 	binding.Encoder = &funcEncoder{fun: func(ptr unsafe.Pointer, stream *Stream) { | ||||
| 		str := *((*string)(ptr)) | ||||
| 		val, _ := strconv.Atoi(str) | ||||
| 		stream.WriteInt(val) | ||||
| 			} | ||||
| 			decode := func(ptr unsafe.Pointer, iter *Iterator) { | ||||
| 	}} | ||||
| 	binding.Decoder = &funcDecoder{func(ptr unsafe.Pointer, iter *Iterator) { | ||||
| 		*((*string)(ptr)) = strconv.Itoa(iter.ReadInt()) | ||||
| 	}} | ||||
| 	binding.ToNames = []string{"field-1"} | ||||
| 	binding.FromNames = []string{"field-1"} | ||||
| } | ||||
| 			return []string{"field-1"}, encode, decode | ||||
| 		} | ||||
| 		return nil, nil, nil | ||||
| 	}) | ||||
|  | ||||
| func Test_customize_field_by_extension(t *testing.T) { | ||||
| 	should := require.New(t) | ||||
| 	RegisterExtension(&testExtension{}) | ||||
| 	obj := TestObject1{} | ||||
| 	err := UnmarshalFromString(`{"field-1": 100}`, &obj) | ||||
| 	should.Nil(err) | ||||
| @@ -111,24 +118,24 @@ func Test_customize_field_by_extension(t *testing.T) { | ||||
| 	should.Equal(`{"field-1":100}`, str) | ||||
| } | ||||
|  | ||||
| func Test_unexported_fields(t *testing.T) { | ||||
| 	jsoniter := Config{SupportUnexportedStructFields: true}.Froze() | ||||
| 	should := require.New(t) | ||||
| 	type TestObject struct { | ||||
| 		field1 string | ||||
| 		field2 string `json:"field-2"` | ||||
| 	} | ||||
| 	obj := TestObject{} | ||||
| 	obj.field1 = "hello" | ||||
| 	should.Nil(jsoniter.UnmarshalFromString(`{}`, &obj)) | ||||
| 	should.Equal("hello", obj.field1) | ||||
| 	should.Nil(jsoniter.UnmarshalFromString(`{"field1": "world", "field-2": "abc"}`, &obj)) | ||||
| 	should.Equal("world", obj.field1) | ||||
| 	should.Equal("abc", obj.field2) | ||||
| 	str, err := jsoniter.MarshalToString(obj) | ||||
| 	should.Nil(err) | ||||
| 	should.Contains(str, `"field-2":"abc"`) | ||||
| } | ||||
| //func Test_unexported_fields(t *testing.T) { | ||||
| //	jsoniter := Config{SupportUnexportedStructFields: true}.Froze() | ||||
| //	should := require.New(t) | ||||
| //	type TestObject struct { | ||||
| //		field1 string | ||||
| //		field2 string `json:"field-2"` | ||||
| //	} | ||||
| //	obj := TestObject{} | ||||
| //	obj.field1 = "hello" | ||||
| //	should.Nil(jsoniter.UnmarshalFromString(`{}`, &obj)) | ||||
| //	should.Equal("hello", obj.field1) | ||||
| //	should.Nil(jsoniter.UnmarshalFromString(`{"field1": "world", "field-2": "abc"}`, &obj)) | ||||
| //	should.Equal("world", obj.field1) | ||||
| //	should.Equal("abc", obj.field2) | ||||
| //	str, err := jsoniter.MarshalToString(obj) | ||||
| //	should.Nil(err) | ||||
| //	should.Contains(str, `"field-2":"abc"`) | ||||
| //} | ||||
|  | ||||
| type ObjectImplementedMarshaler int | ||||
|  | ||||
| @@ -155,6 +162,7 @@ func Test_marshaler_and_encoder(t *testing.T) { | ||||
| 	type TestObject struct { | ||||
| 		Field *ObjectImplementedMarshaler | ||||
| 	} | ||||
| 	ConfigDefault.cleanEncoders() | ||||
| 	should := require.New(t) | ||||
| 	RegisterTypeEncoderFunc("jsoniter.ObjectImplementedMarshaler", func(ptr unsafe.Pointer, stream *Stream) { | ||||
| 		stream.WriteString("hello from encoder") | ||||
| @@ -198,6 +206,7 @@ func Test_unmarshaler_and_decoder(t *testing.T) { | ||||
| 		Field  *ObjectImplementedUnmarshaler | ||||
| 		Field2 string | ||||
| 	} | ||||
| 	ConfigDefault.cleanDecoders() | ||||
| 	should := require.New(t) | ||||
| 	RegisterTypeDecoderFunc("jsoniter.ObjectImplementedUnmarshaler", func(ptr unsafe.Pointer, iter *Iterator) { | ||||
| 		*(*ObjectImplementedUnmarshaler)(ptr) = 10 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user