package test import ( "github.com/json-iterator/go" "github.com/modern-go/reflect2" "github.com/stretchr/testify/require" "reflect" "strconv" "testing" "unsafe" ) type TestObject1 struct { Field1 string } type testExtension struct { jsoniter.DummyExtension } func (extension *testExtension) UpdateStructDescriptor(structDescriptor *jsoniter.StructDescriptor) { if structDescriptor.Type.String() != "test.TestObject1" { return } binding := structDescriptor.GetField("Field1") binding.Encoder = &funcEncoder{fun: func(ptr unsafe.Pointer, stream *jsoniter.Stream) { str := *((*string)(ptr)) val, _ := strconv.Atoi(str) stream.WriteInt(val) }} binding.Decoder = &funcDecoder{func(ptr unsafe.Pointer, iter *jsoniter.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) cfg := jsoniter.Config{}.Froze() cfg.RegisterExtension(&testExtension{}) obj := TestObject1{} err := cfg.UnmarshalFromString(`{"field-1": 100}`, &obj) should.Nil(err) should.Equal("100", obj.Field1) str, err := cfg.MarshalToString(obj) should.Nil(err) should.Equal(`{"field-1":100}`, str) } func Test_customize_map_key_encoder(t *testing.T) { should := require.New(t) cfg := jsoniter.Config{}.Froze() cfg.RegisterExtension(&testMapKeyExtension{}) m := map[int]int{1: 2} output, err := cfg.MarshalToString(m) should.NoError(err) should.Equal(`{"2":2}`, output) m = map[int]int{} should.NoError(cfg.UnmarshalFromString(output, &m)) should.Equal(map[int]int{1: 2}, m) } type testMapKeyExtension struct { jsoniter.DummyExtension } func (extension *testMapKeyExtension) CreateMapKeyEncoder(typ reflect2.Type) jsoniter.ValEncoder { if typ.Kind() == reflect.Int { return &funcEncoder{ fun: func(ptr unsafe.Pointer, stream *jsoniter.Stream) { stream.WriteRaw(`"`) stream.WriteInt(*(*int)(ptr) + 1) stream.WriteRaw(`"`) }, } } return nil } func (extension *testMapKeyExtension) CreateMapKeyDecoder(typ reflect2.Type) jsoniter.ValDecoder { if typ.Kind() == reflect.Int { return &funcDecoder{ fun: func(ptr unsafe.Pointer, iter *jsoniter.Iterator) { i, err := strconv.Atoi(iter.ReadString()) if err != nil { iter.ReportError("read map key", err.Error()) return } i-- *(*int)(ptr) = i }, } } return nil } type funcDecoder struct { fun jsoniter.DecoderFunc } func (decoder *funcDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) { decoder.fun(ptr, iter) } type funcEncoder struct { fun jsoniter.EncoderFunc isEmptyFunc func(ptr unsafe.Pointer) bool } func (encoder *funcEncoder) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) { encoder.fun(ptr, stream) } func (encoder *funcEncoder) IsEmpty(ptr unsafe.Pointer) bool { if encoder.isEmptyFunc == nil { return false } return encoder.isEmptyFunc(ptr) }