1
0
mirror of https://github.com/json-iterator/go.git synced 2025-03-20 20:54:55 +02:00

#58 string mode support both encoding and decoding

This commit is contained in:
Tao Wen 2017-06-17 11:38:09 +08:00
parent b31b1301e2
commit 3d5f6d3a4a
3 changed files with 71 additions and 7 deletions

View File

@ -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
}

View File

@ -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}

View File

@ -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)
}