From 3d5f6d3a4a6a7a793d0b7527344b31311fc5b263 Mon Sep 17 00:00:00 2001 From: Tao Wen Date: Sat, 17 Jun 2017 11:38:09 +0800 Subject: [PATCH] #58 string mode support both encoding and decoding --- feature_reflect_native.go | 26 ++++++++++++++++++++++---- feature_reflect_object.go | 14 +++++++++++--- jsoniter_bool_test.go | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 7 deletions(-) diff --git a/feature_reflect_native.go b/feature_reflect_native.go index 4578c1a..aafe199 100644 --- a/feature_reflect_native.go +++ b/feature_reflect_native.go @@ -427,14 +427,14 @@ func (encoder *base64Codec) isEmpty(ptr unsafe.Pointer) bool { return len(*((*[]byte)(ptr))) == 0 } -type stringNumberDecoder struct { +type stringModeDecoder struct { elemDecoder Decoder } -func (decoder *stringNumberDecoder) decode(ptr unsafe.Pointer, iter *Iterator) { +func (decoder *stringModeDecoder) decode(ptr unsafe.Pointer, iter *Iterator) { c := iter.nextToken() if c != '"' { - iter.reportError("stringNumberDecoder", `expect "`) + iter.reportError("stringModeDecoder", `expect "`) return } decoder.elemDecoder.decode(ptr, iter) @@ -443,11 +443,29 @@ func (decoder *stringNumberDecoder) decode(ptr unsafe.Pointer, iter *Iterator) { } c = iter.readByte() if c != '"' { - iter.reportError("stringNumberDecoder", `expect "`) + iter.reportError("stringModeDecoder", `expect "`) return } } +type stringModeEncoder struct { + elemEncoder Encoder +} + +func (encoder *stringModeEncoder) encode(ptr unsafe.Pointer, stream *Stream) { + stream.writeByte('"') + encoder.elemEncoder.encode(ptr, stream) + stream.writeByte('"') +} + +func (encoder *stringModeEncoder) encodeInterface(val interface{}, stream *Stream) { + writeToStream(val, stream, encoder) +} + +func (encoder *stringModeEncoder) isEmpty(ptr unsafe.Pointer) bool { + return encoder.elemEncoder.isEmpty(ptr) +} + type marshalerEncoder struct { templateInterface emptyInterface } diff --git a/feature_reflect_object.go b/feature_reflect_object.go index 9ea375f..8a2c94e 100644 --- a/feature_reflect_object.go +++ b/feature_reflect_object.go @@ -37,9 +37,12 @@ func encoderOfStruct(cfg *frozenConfig, typ reflect.Type) (Encoder, error) { // if fieldNames set by extension, use theirs, otherwise try tags fieldNames := calcFieldNames(field.Name, tagParts[0], extensionProvidedFieldNames) omitempty := false - for _, tagPart := range tagParts { + stringMode := false + for _, tagPart := range tagParts[1:] { if tagPart == "omitempty" { omitempty = true + } else if tagPart == "string" { + stringMode = true } } encoder := fieldEncoders[fieldEncoderKey] @@ -54,6 +57,9 @@ func encoderOfStruct(cfg *frozenConfig, typ reflect.Type) (Encoder, error) { encoder = &optionalEncoder{encoder} } } + if stringMode { + encoder = &stringModeEncoder{encoder} + } for _, fieldName := range fieldNames { fields[fieldName] = &structFieldEncoder{field, fieldName, encoder, omitempty} } @@ -114,8 +120,10 @@ func decoderOfStruct(cfg *frozenConfig, typ reflect.Type) (Decoder, error) { return prefix(fmt.Sprintf("{%s}", field.Name)).addToDecoder(decoder, err) } } - if len(tagParts) > 1 && tagParts[1] == "string" { - decoder = &stringNumberDecoder{decoder} + for _, tagPart := range tagParts[1:] { + if tagPart == "string" { + decoder = &stringModeDecoder{decoder} + } } for _, fieldName := range fieldNames { fields[fieldName] = &structFieldDecoder{&field, decoder} diff --git a/jsoniter_bool_test.go b/jsoniter_bool_test.go index bce0c3e..7785bd8 100644 --- a/jsoniter_bool_test.go +++ b/jsoniter_bool_test.go @@ -4,6 +4,7 @@ import ( "bytes" "github.com/json-iterator/go/require" "testing" + "encoding/json" ) func Test_true(t *testing.T) { @@ -47,3 +48,40 @@ func Test_write_val_bool(t *testing.T) { should.Nil(stream.Error) should.Equal("true", buf.String()) } + +func Test_encode_string_bool(t *testing.T) { + type TestObject struct { + Field bool `json:",omitempty,string"` + } + should := require.New(t) + output, err := json.Marshal(TestObject{true}) + should.Nil(err) + should.Equal(`{"Field":"true"}`, string(output)) + output, err = Marshal(TestObject{true}) + should.Nil(err) + should.Equal(`{"Field":"true"}`, string(output)) +} + +func Test_decode_string_bool(t *testing.T) { + type TestObject struct { + Field bool `json:",omitempty,string"` + } + should := require.New(t) + obj := TestObject{} + err := json.Unmarshal([]byte(`{"Field":"true"}`), &obj) + should.Nil(err) + should.True(obj.Field) + + obj = TestObject{} + err = json.Unmarshal([]byte(`{"Field":true}`), &obj) + should.NotNil(err) + + obj = TestObject{} + err = Unmarshal([]byte(`{"Field":"true"}`), &obj) + should.Nil(err) + should.True(obj.Field) + + obj = TestObject{} + err = Unmarshal([]byte(`{"Field":true}`), &obj) + should.NotNil(err) +}