mirror of
https://github.com/json-iterator/go.git
synced 2025-04-17 11:26:35 +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 {
|
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)
|
|
||||||
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 {
|
if err != nil {
|
||||||
return prefix(fmt.Sprintf("{%s}", field.Name)).addToEncoder(encoder, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
// map is stored as pointer in the struct
|
for _, binding := range structDescriptor.Fields {
|
||||||
if field.Type.Kind() == reflect.Map {
|
for _, fieldName := range binding.ToNames {
|
||||||
encoder = &optionalEncoder{encoder}
|
fields[fieldName] = &structFieldEncoder{binding.Field, fieldName, binding.Encoder, binding.ShouldOmitEmpty}
|
||||||
}
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
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 {
|
if err != nil {
|
||||||
return prefix(fmt.Sprintf("{%s}", field.Name)).addToDecoder(decoder, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
for _, binding := range structDescriptor.Fields {
|
||||||
for _, tagPart := range tagParts[1:] {
|
for _, fieldName := range binding.FromNames {
|
||||||
if tagPart == "string" {
|
fields[fieldName] = &structFieldDecoder{binding.Field, binding.Decoder}
|
||||||
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: {},
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_customize_field_by_extension(t *testing.T) {
|
type testExtension struct {
|
||||||
should := require.New(t)
|
DummyExtension
|
||||||
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) {
|
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))
|
str := *((*string)(ptr))
|
||||||
val, _ := strconv.Atoi(str)
|
val, _ := strconv.Atoi(str)
|
||||||
stream.WriteInt(val)
|
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())
|
*((*string)(ptr)) = strconv.Itoa(iter.ReadInt())
|
||||||
}
|
}}
|
||||||
return []string{"field-1"}, encode, decode
|
binding.ToNames = []string{"field-1"}
|
||||||
}
|
binding.FromNames = []string{"field-1"}
|
||||||
return nil, nil, nil
|
}
|
||||||
})
|
|
||||||
|
func Test_customize_field_by_extension(t *testing.T) {
|
||||||
|
should := require.New(t)
|
||||||
|
RegisterExtension(&testExtension{})
|
||||||
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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user