mirror of
https://github.com/json-iterator/go.git
synced 2025-02-19 19:59:49 +02:00
#66 Make extension api like the java version
This commit is contained in:
parent
499412ec4c
commit
be221df432
@ -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)
|
||||
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}
|
||||
structDescriptor, err := describeStruct(cfg, typ)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
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)
|
||||
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}
|
||||
structDescriptor, err := describeStruct(cfg, typ)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
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: {},
|
||||
@ -222,7 +109,7 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
|
||||
}
|
||||
}
|
||||
return &threeFieldsStructDecoder{typ,
|
||||
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3}, nil
|
||||
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3}, nil
|
||||
case 4:
|
||||
var fieldName1 int32
|
||||
var fieldName2 int32
|
||||
@ -255,8 +142,8 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
|
||||
}
|
||||
}
|
||||
return &fourFieldsStructDecoder{typ,
|
||||
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
|
||||
fieldName4, fieldDecoder4}, nil
|
||||
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
|
||||
fieldName4, fieldDecoder4}, nil
|
||||
case 5:
|
||||
var fieldName1 int32
|
||||
var fieldName2 int32
|
||||
@ -294,8 +181,8 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
|
||||
}
|
||||
}
|
||||
return &fiveFieldsStructDecoder{typ,
|
||||
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
|
||||
fieldName4, fieldDecoder4, fieldName5, fieldDecoder5}, nil
|
||||
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
|
||||
fieldName4, fieldDecoder4, fieldName5, fieldDecoder5}, nil
|
||||
case 6:
|
||||
var fieldName1 int32
|
||||
var fieldName2 int32
|
||||
@ -338,8 +225,8 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
|
||||
}
|
||||
}
|
||||
return &sixFieldsStructDecoder{typ,
|
||||
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
|
||||
fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6}, nil
|
||||
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
|
||||
fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6}, nil
|
||||
case 7:
|
||||
var fieldName1 int32
|
||||
var fieldName2 int32
|
||||
@ -387,9 +274,9 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
|
||||
}
|
||||
}
|
||||
return &sevenFieldsStructDecoder{typ,
|
||||
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
|
||||
fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6,
|
||||
fieldName7, fieldDecoder7}, nil
|
||||
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
|
||||
fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6,
|
||||
fieldName7, fieldDecoder7}, nil
|
||||
case 8:
|
||||
var fieldName1 int32
|
||||
var fieldName2 int32
|
||||
@ -442,9 +329,9 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
|
||||
}
|
||||
}
|
||||
return &eightFieldsStructDecoder{typ,
|
||||
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
|
||||
fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6,
|
||||
fieldName7, fieldDecoder7, fieldName8, fieldDecoder8}, nil
|
||||
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
|
||||
fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6,
|
||||
fieldName7, fieldDecoder7, fieldName8, fieldDecoder8}, nil
|
||||
case 9:
|
||||
var fieldName1 int32
|
||||
var fieldName2 int32
|
||||
@ -502,9 +389,9 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
|
||||
}
|
||||
}
|
||||
return &nineFieldsStructDecoder{typ,
|
||||
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
|
||||
fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6,
|
||||
fieldName7, fieldDecoder7, fieldName8, fieldDecoder8, fieldName9, fieldDecoder9}, nil
|
||||
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
|
||||
fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6,
|
||||
fieldName7, fieldDecoder7, fieldName8, fieldDecoder8, fieldName9, fieldDecoder9}, nil
|
||||
case 10:
|
||||
var fieldName1 int32
|
||||
var fieldName2 int32
|
||||
@ -567,10 +454,10 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
|
||||
}
|
||||
}
|
||||
return &tenFieldsStructDecoder{typ,
|
||||
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
|
||||
fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6,
|
||||
fieldName7, fieldDecoder7, fieldName8, fieldDecoder8, fieldName9, fieldDecoder9,
|
||||
fieldName10, fieldDecoder10}, nil
|
||||
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
|
||||
fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6,
|
||||
fieldName7, fieldDecoder7, fieldName8, fieldDecoder8, fieldName9, fieldDecoder9,
|
||||
fieldName10, fieldDecoder10}, nil
|
||||
}
|
||||
return &generalStructDecoder{typ, fields}, nil
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
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
|
||||
})
|
||||
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
|
||||
|
Loading…
x
Reference in New Issue
Block a user