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 { | type Config struct { | ||||||
| 	IndentionStep                 int | 	IndentionStep                 int | ||||||
| 	MarshalFloatWith6Digits       bool | 	MarshalFloatWith6Digits       bool | ||||||
| 	SupportUnexportedStructFields bool |  | ||||||
| 	EscapeHtml                    bool | 	EscapeHtml                    bool | ||||||
| 	SortMapKeys                   bool | 	SortMapKeys                   bool | ||||||
| 	UseNumber                     bool | 	UseNumber                     bool | ||||||
| @@ -24,7 +23,7 @@ type frozenConfig struct { | |||||||
| 	indentionStep      int | 	indentionStep      int | ||||||
| 	decoderCache       unsafe.Pointer | 	decoderCache       unsafe.Pointer | ||||||
| 	encoderCache       unsafe.Pointer | 	encoderCache       unsafe.Pointer | ||||||
| 	extensions         []ExtensionFunc | 	extensions         []Extension | ||||||
| 	streamPool         chan *Stream | 	streamPool         chan *Stream | ||||||
| 	iteratorPool       chan *Iterator | 	iteratorPool       chan *Iterator | ||||||
| } | } | ||||||
| @@ -65,9 +64,6 @@ func (cfg Config) Froze() *frozenConfig { | |||||||
| 	if cfg.MarshalFloatWith6Digits { | 	if cfg.MarshalFloatWith6Digits { | ||||||
| 		frozenConfig.marshalFloatWith6Digits() | 		frozenConfig.marshalFloatWith6Digits() | ||||||
| 	} | 	} | ||||||
| 	if cfg.SupportUnexportedStructFields { |  | ||||||
| 		frozenConfig.supportUnexportedStructFields() |  | ||||||
| 	} |  | ||||||
| 	if cfg.EscapeHtml { | 	if cfg.EscapeHtml { | ||||||
| 		frozenConfig.escapeHtml() | 		frozenConfig.escapeHtml() | ||||||
| 	} | 	} | ||||||
| @@ -88,17 +84,10 @@ func (cfg *frozenConfig) useNumber() { | |||||||
| 	}}) | 	}}) | ||||||
| } | } | ||||||
|  |  | ||||||
| // RegisterExtension can register a custom extension | func (cfg *frozenConfig) registerExtension(extension Extension) { | ||||||
| func (cfg *frozenConfig) registerExtension(extension ExtensionFunc) { |  | ||||||
| 	cfg.extensions = append(cfg.extensions, 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 { | type lossyFloat32Encoder struct { | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -4,28 +4,54 @@ import ( | |||||||
| 	"reflect" | 	"reflect" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"unsafe" | 	"unsafe" | ||||||
|  | 	"strings" | ||||||
|  | 	"unicode" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| var typeDecoders map[string]ValDecoder | var typeDecoders = map[string]ValDecoder{} | ||||||
| var fieldDecoders map[string]ValDecoder | var fieldDecoders = map[string]ValDecoder{} | ||||||
| var typeEncoders map[string]ValEncoder | var typeEncoders = map[string]ValEncoder{} | ||||||
| var fieldEncoders map[string]ValEncoder | var fieldEncoders = map[string]ValEncoder{} | ||||||
| var extensions []ExtensionFunc | 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 { | type funcDecoder struct { | ||||||
| 	fun DecoderFunc | 	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) { | func RegisterTypeDecoderFunc(typ string, fun DecoderFunc) { | ||||||
| 	typeDecoders[typ] = &funcDecoder{fun} | 	typeDecoders[typ] = &funcDecoder{fun} | ||||||
| } | } | ||||||
| @@ -58,36 +84,134 @@ func RegisterFieldEncoder(typ string, field string, encoder ValEncoder) { | |||||||
| 	fieldEncoders[fmt.Sprintf("%s/%s", typ, field)] = encoder | 	fieldEncoders[fmt.Sprintf("%s/%s", typ, field)] = encoder | ||||||
| } | } | ||||||
|  |  | ||||||
| func RegisterExtension(extension ExtensionFunc) { | func RegisterExtension(extension Extension) { | ||||||
| 	extensions = append(extensions, extension) | 	extensions = append(extensions, extension) | ||||||
| } | } | ||||||
|  |  | ||||||
| func getTypeDecoderFromExtension(typ reflect.Type) ValDecoder { | func getTypeDecoderFromExtension(typ reflect.Type) ValDecoder { | ||||||
|  | 	for _, extension := range extensions { | ||||||
|  | 		decoder := extension.CreateDecoder(typ) | ||||||
|  | 		if decoder != nil { | ||||||
|  | 			return decoder | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| 	typeName := typ.String() | 	typeName := typ.String() | ||||||
| 	typeDecoder := typeDecoders[typeName] | 	decoder := typeDecoders[typeName] | ||||||
| 	if typeDecoder != nil { | 	if decoder != nil { | ||||||
| 		return typeDecoder | 		return decoder | ||||||
| 	} | 	} | ||||||
| 	if typ.Kind() == reflect.Ptr { | 	if typ.Kind() == reflect.Ptr { | ||||||
| 		typeDecoder := typeDecoders[typ.Elem().String()] | 		decoder := typeDecoders[typ.Elem().String()] | ||||||
| 		if typeDecoder != nil { | 		if decoder != nil { | ||||||
| 			return &optionalDecoder{typ.Elem(), typeDecoder} | 			return &optionalDecoder{typ.Elem(), decoder} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func getTypeEncoderFromExtension(typ reflect.Type) ValEncoder { | func getTypeEncoderFromExtension(typ reflect.Type) ValEncoder { | ||||||
|  | 	for _, extension := range extensions { | ||||||
|  | 		encoder := extension.CreateEncoder(typ) | ||||||
|  | 		if encoder != nil { | ||||||
|  | 			return encoder | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| 	typeName := typ.String() | 	typeName := typ.String() | ||||||
| 	typeEncoder := typeEncoders[typeName] | 	encoder := typeEncoders[typeName] | ||||||
| 	if typeEncoder != nil { | 	if encoder != nil { | ||||||
| 		return typeEncoder | 		return encoder | ||||||
| 	} | 	} | ||||||
| 	if typ.Kind() == reflect.Ptr { | 	if typ.Kind() == reflect.Ptr { | ||||||
| 		typeEncoder := typeEncoders[typ.Elem().String()] | 		encoder := typeEncoders[typ.Elem().String()] | ||||||
| 		if typeEncoder != nil { | 		if encoder != nil { | ||||||
| 			return &optionalEncoder{typeEncoder} | 			return &optionalEncoder{encoder} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return nil | 	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" | 	"fmt" | ||||||
| 	"io" | 	"io" | ||||||
| 	"reflect" | 	"reflect" | ||||||
| 	"strings" |  | ||||||
| 	"unicode" |  | ||||||
| 	"unsafe" | 	"unsafe" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func encoderOfStruct(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) { | func encoderOfStruct(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) { | ||||||
| 	structEncoder_ := &structEncoder{} | 	structEncoder_ := &structEncoder{} | ||||||
| 	fields := map[string]*structFieldEncoder{} | 	fields := map[string]*structFieldEncoder{} | ||||||
| 	for _, field := range listStructFields(typ) { | 	structDescriptor, err := describeStruct(cfg, typ) | ||||||
| 		fieldEncoderKey := fmt.Sprintf("%s/%s", typ.String(), field.Name) | 	if err != nil { | ||||||
| 		var extensionProvidedFieldNames []string | 		return nil, err | ||||||
| 		for _, extension := range extensions { | 	} | ||||||
| 			alternativeFieldNames, fun, _ := extension(typ, field) | 	for _, binding := range structDescriptor.Fields { | ||||||
| 			if alternativeFieldNames != nil { | 		for _, fieldName := range binding.ToNames { | ||||||
| 				extensionProvidedFieldNames = alternativeFieldNames | 			fields[fieldName] = &structFieldEncoder{binding.Field, fieldName, binding.Encoder, binding.ShouldOmitEmpty} | ||||||
| 			} |  | ||||||
| 			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) |  | ||||||
| 			if err != nil { |  | ||||||
| 				return prefix(fmt.Sprintf("{%s}", field.Name)).addToEncoder(encoder, 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} |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	if len(fields) == 0 { | 	if len(fields) == 0 { | ||||||
| @@ -73,88 +28,20 @@ func encoderOfStruct(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) { | |||||||
| 	return structEncoder_, nil | 	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) { | func decoderOfStruct(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error) { | ||||||
| 	fields := map[string]*structFieldDecoder{} | 	fields := map[string]*structFieldDecoder{} | ||||||
| 	for _, field := range listStructFields(typ) { | 	structDescriptor, err := describeStruct(cfg, typ) | ||||||
| 		fieldDecoderKey := fmt.Sprintf("%s/%s", typ.String(), field.Name) | 	if err != nil { | ||||||
| 		var extensionProviedFieldNames []string | 		return nil, err | ||||||
| 		for _, extension := range extensions { | 	} | ||||||
| 			alternativeFieldNames, _, fun := extension(typ, field) | 	for _, binding := range structDescriptor.Fields { | ||||||
| 			if alternativeFieldNames != nil { | 		for _, fieldName := range binding.FromNames { | ||||||
| 				extensionProviedFieldNames = alternativeFieldNames | 			fields[fieldName] = &structFieldDecoder{binding.Field, binding.Decoder} | ||||||
| 			} |  | ||||||
| 			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) |  | ||||||
| 			if err != nil { |  | ||||||
| 				return prefix(fmt.Sprintf("{%s}", field.Name)).addToDecoder(decoder, err) |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		for _, tagPart := range tagParts[1:] { |  | ||||||
| 			if tagPart == "string" { |  | ||||||
| 				decoder = &stringModeDecoder{decoder} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		for _, fieldName := range fieldNames { |  | ||||||
| 			fields[fieldName] = &structFieldDecoder{field, decoder} |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return createStructDecoder(typ, fields) | 	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) { | func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder) (ValDecoder, error) { | ||||||
| 	knownHash := map[int32]struct{}{ | 	knownHash := map[int32]struct{}{ | ||||||
| 		0: {}, | 		0: {}, | ||||||
| @@ -222,7 +109,7 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		return &threeFieldsStructDecoder{typ, | 		return &threeFieldsStructDecoder{typ, | ||||||
| 			fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3}, nil | 										 fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3}, nil | ||||||
| 	case 4: | 	case 4: | ||||||
| 		var fieldName1 int32 | 		var fieldName1 int32 | ||||||
| 		var fieldName2 int32 | 		var fieldName2 int32 | ||||||
| @@ -255,8 +142,8 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		return &fourFieldsStructDecoder{typ, | 		return &fourFieldsStructDecoder{typ, | ||||||
| 			fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, | 										fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, | ||||||
| 			fieldName4, fieldDecoder4}, nil | 										fieldName4, fieldDecoder4}, nil | ||||||
| 	case 5: | 	case 5: | ||||||
| 		var fieldName1 int32 | 		var fieldName1 int32 | ||||||
| 		var fieldName2 int32 | 		var fieldName2 int32 | ||||||
| @@ -294,8 +181,8 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		return &fiveFieldsStructDecoder{typ, | 		return &fiveFieldsStructDecoder{typ, | ||||||
| 			fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, | 										fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, | ||||||
| 			fieldName4, fieldDecoder4, fieldName5, fieldDecoder5}, nil | 										fieldName4, fieldDecoder4, fieldName5, fieldDecoder5}, nil | ||||||
| 	case 6: | 	case 6: | ||||||
| 		var fieldName1 int32 | 		var fieldName1 int32 | ||||||
| 		var fieldName2 int32 | 		var fieldName2 int32 | ||||||
| @@ -338,8 +225,8 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		return &sixFieldsStructDecoder{typ, | 		return &sixFieldsStructDecoder{typ, | ||||||
| 			fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, | 									   fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, | ||||||
| 			fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6}, nil | 									   fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6}, nil | ||||||
| 	case 7: | 	case 7: | ||||||
| 		var fieldName1 int32 | 		var fieldName1 int32 | ||||||
| 		var fieldName2 int32 | 		var fieldName2 int32 | ||||||
| @@ -387,9 +274,9 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		return &sevenFieldsStructDecoder{typ, | 		return &sevenFieldsStructDecoder{typ, | ||||||
| 			fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, | 										 fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, | ||||||
| 			fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6, | 										 fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6, | ||||||
| 			fieldName7, fieldDecoder7}, nil | 										 fieldName7, fieldDecoder7}, nil | ||||||
| 	case 8: | 	case 8: | ||||||
| 		var fieldName1 int32 | 		var fieldName1 int32 | ||||||
| 		var fieldName2 int32 | 		var fieldName2 int32 | ||||||
| @@ -442,9 +329,9 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		return &eightFieldsStructDecoder{typ, | 		return &eightFieldsStructDecoder{typ, | ||||||
| 			fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, | 										 fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, | ||||||
| 			fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6, | 										 fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6, | ||||||
| 			fieldName7, fieldDecoder7, fieldName8, fieldDecoder8}, nil | 										 fieldName7, fieldDecoder7, fieldName8, fieldDecoder8}, nil | ||||||
| 	case 9: | 	case 9: | ||||||
| 		var fieldName1 int32 | 		var fieldName1 int32 | ||||||
| 		var fieldName2 int32 | 		var fieldName2 int32 | ||||||
| @@ -502,9 +389,9 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		return &nineFieldsStructDecoder{typ, | 		return &nineFieldsStructDecoder{typ, | ||||||
| 			fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, | 										fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, | ||||||
| 			fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6, | 										fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6, | ||||||
| 			fieldName7, fieldDecoder7, fieldName8, fieldDecoder8, fieldName9, fieldDecoder9}, nil | 										fieldName7, fieldDecoder7, fieldName8, fieldDecoder8, fieldName9, fieldDecoder9}, nil | ||||||
| 	case 10: | 	case 10: | ||||||
| 		var fieldName1 int32 | 		var fieldName1 int32 | ||||||
| 		var fieldName2 int32 | 		var fieldName2 int32 | ||||||
| @@ -567,10 +454,10 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		return &tenFieldsStructDecoder{typ, | 		return &tenFieldsStructDecoder{typ, | ||||||
| 			fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, | 									   fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3, | ||||||
| 			fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6, | 									   fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6, | ||||||
| 			fieldName7, fieldDecoder7, fieldName8, fieldDecoder8, fieldName9, fieldDecoder9, | 									   fieldName7, fieldDecoder7, fieldName8, fieldDecoder8, fieldName9, fieldDecoder9, | ||||||
| 			fieldName10, fieldDecoder10}, nil | 									   fieldName10, fieldDecoder10}, nil | ||||||
| 	} | 	} | ||||||
| 	return &generalStructDecoder{typ, fields}, nil | 	return &generalStructDecoder{typ, fields}, nil | ||||||
| } | } | ||||||
|   | |||||||
| @@ -3,7 +3,6 @@ package jsoniter | |||||||
| import ( | import ( | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"github.com/json-iterator/go/require" | 	"github.com/json-iterator/go/require" | ||||||
| 	"reflect" |  | ||||||
| 	"strconv" | 	"strconv" | ||||||
| 	"testing" | 	"testing" | ||||||
| 	"time" | 	"time" | ||||||
| @@ -86,22 +85,30 @@ type TestObject1 struct { | |||||||
| 	field1 string | 	field1 string | ||||||
| } | } | ||||||
|  |  | ||||||
|  | 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) | ||||||
|  | 	}} | ||||||
|  | 	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"} | ||||||
|  | } | ||||||
|  |  | ||||||
| func Test_customize_field_by_extension(t *testing.T) { | func Test_customize_field_by_extension(t *testing.T) { | ||||||
| 	should := require.New(t) | 	should := require.New(t) | ||||||
| 	RegisterExtension(func(type_ reflect.Type, field *reflect.StructField) ([]string, EncoderFunc, DecoderFunc) { | 	RegisterExtension(&testExtension{}) | ||||||
| 		if type_.String() == "jsoniter.TestObject1" && field.Name == "field1" { |  | ||||||
| 			encode := func(ptr unsafe.Pointer, stream *Stream) { |  | ||||||
| 				str := *((*string)(ptr)) |  | ||||||
| 				val, _ := strconv.Atoi(str) |  | ||||||
| 				stream.WriteInt(val) |  | ||||||
| 			} |  | ||||||
| 			decode := func(ptr unsafe.Pointer, iter *Iterator) { |  | ||||||
| 				*((*string)(ptr)) = strconv.Itoa(iter.ReadInt()) |  | ||||||
| 			} |  | ||||||
| 			return []string{"field-1"}, encode, decode |  | ||||||
| 		} |  | ||||||
| 		return nil, nil, nil |  | ||||||
| 	}) |  | ||||||
| 	obj := TestObject1{} | 	obj := TestObject1{} | ||||||
| 	err := UnmarshalFromString(`{"field-1": 100}`, &obj) | 	err := UnmarshalFromString(`{"field-1": 100}`, &obj) | ||||||
| 	should.Nil(err) | 	should.Nil(err) | ||||||
| @@ -111,24 +118,24 @@ func Test_customize_field_by_extension(t *testing.T) { | |||||||
| 	should.Equal(`{"field-1":100}`, str) | 	should.Equal(`{"field-1":100}`, str) | ||||||
| } | } | ||||||
|  |  | ||||||
| func Test_unexported_fields(t *testing.T) { | //func Test_unexported_fields(t *testing.T) { | ||||||
| 	jsoniter := Config{SupportUnexportedStructFields: true}.Froze() | //	jsoniter := Config{SupportUnexportedStructFields: true}.Froze() | ||||||
| 	should := require.New(t) | //	should := require.New(t) | ||||||
| 	type TestObject struct { | //	type TestObject struct { | ||||||
| 		field1 string | //		field1 string | ||||||
| 		field2 string `json:"field-2"` | //		field2 string `json:"field-2"` | ||||||
| 	} | //	} | ||||||
| 	obj := TestObject{} | //	obj := TestObject{} | ||||||
| 	obj.field1 = "hello" | //	obj.field1 = "hello" | ||||||
| 	should.Nil(jsoniter.UnmarshalFromString(`{}`, &obj)) | //	should.Nil(jsoniter.UnmarshalFromString(`{}`, &obj)) | ||||||
| 	should.Equal("hello", obj.field1) | //	should.Equal("hello", obj.field1) | ||||||
| 	should.Nil(jsoniter.UnmarshalFromString(`{"field1": "world", "field-2": "abc"}`, &obj)) | //	should.Nil(jsoniter.UnmarshalFromString(`{"field1": "world", "field-2": "abc"}`, &obj)) | ||||||
| 	should.Equal("world", obj.field1) | //	should.Equal("world", obj.field1) | ||||||
| 	should.Equal("abc", obj.field2) | //	should.Equal("abc", obj.field2) | ||||||
| 	str, err := jsoniter.MarshalToString(obj) | //	str, err := jsoniter.MarshalToString(obj) | ||||||
| 	should.Nil(err) | //	should.Nil(err) | ||||||
| 	should.Contains(str, `"field-2":"abc"`) | //	should.Contains(str, `"field-2":"abc"`) | ||||||
| } | //} | ||||||
|  |  | ||||||
| type ObjectImplementedMarshaler int | type ObjectImplementedMarshaler int | ||||||
|  |  | ||||||
| @@ -155,6 +162,7 @@ func Test_marshaler_and_encoder(t *testing.T) { | |||||||
| 	type TestObject struct { | 	type TestObject struct { | ||||||
| 		Field *ObjectImplementedMarshaler | 		Field *ObjectImplementedMarshaler | ||||||
| 	} | 	} | ||||||
|  | 	ConfigDefault.cleanEncoders() | ||||||
| 	should := require.New(t) | 	should := require.New(t) | ||||||
| 	RegisterTypeEncoderFunc("jsoniter.ObjectImplementedMarshaler", func(ptr unsafe.Pointer, stream *Stream) { | 	RegisterTypeEncoderFunc("jsoniter.ObjectImplementedMarshaler", func(ptr unsafe.Pointer, stream *Stream) { | ||||||
| 		stream.WriteString("hello from encoder") | 		stream.WriteString("hello from encoder") | ||||||
| @@ -198,6 +206,7 @@ func Test_unmarshaler_and_decoder(t *testing.T) { | |||||||
| 		Field  *ObjectImplementedUnmarshaler | 		Field  *ObjectImplementedUnmarshaler | ||||||
| 		Field2 string | 		Field2 string | ||||||
| 	} | 	} | ||||||
|  | 	ConfigDefault.cleanDecoders() | ||||||
| 	should := require.New(t) | 	should := require.New(t) | ||||||
| 	RegisterTypeDecoderFunc("jsoniter.ObjectImplementedUnmarshaler", func(ptr unsafe.Pointer, iter *Iterator) { | 	RegisterTypeDecoderFunc("jsoniter.ObjectImplementedUnmarshaler", func(ptr unsafe.Pointer, iter *Iterator) { | ||||||
| 		*(*ObjectImplementedUnmarshaler)(ptr) = 10 | 		*(*ObjectImplementedUnmarshaler)(ptr) = 10 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user