diff --git a/jsoniter_reflect.go b/jsoniter_reflect.go index 34c7f4a..007426d 100644 --- a/jsoniter_reflect.go +++ b/jsoniter_reflect.go @@ -6,6 +6,7 @@ import ( "fmt" "unsafe" "sync/atomic" + "strings" ) type Decoder interface { @@ -110,6 +111,24 @@ func (decoder *boolDecoder) decode(ptr unsafe.Pointer, iter *Iterator) { *((*bool)(ptr)) = iter.ReadBool() } +type stringNumberDecoder struct { + elemDecoder Decoder +} + +func (decoder *stringNumberDecoder) decode(ptr unsafe.Pointer, iter *Iterator) { + c := iter.readByte() + if c != '"' { + iter.ReportError("stringNumberDecoder", `expect "`) + return + } + decoder.elemDecoder.decode(ptr, iter) + c = iter.readByte() + if c != '"' { + iter.ReportError("stringNumberDecoder", `expect "`) + return + } +} + type optionalDecoder struct { valueType reflect.Type valueDecoder Decoder @@ -327,11 +346,21 @@ func decoderOfStruct(type_ reflect.Type) (Decoder, error) { fields := map[string]Decoder{} for i := 0; i < type_.NumField(); i++ { field := type_.Field(i) + tagParts := strings.Split(field.Tag.Get("json"), ",") + jsonFieldName := tagParts[0] + if jsonFieldName == "" { + jsonFieldName = field.Name + } decoder, err := decoderOfPtr(field.Type) if err != nil { return prefix(fmt.Sprintf("{%s}", field.Name)).addTo(decoder, err) } - fields[field.Name] = &structFieldDecoder{field.Offset, decoder} + if len(tagParts) > 1 && tagParts[1] == "string" { + decoder = &stringNumberDecoder{decoder} + } + if jsonFieldName != "-" { + fields[jsonFieldName] = &structFieldDecoder{field.Offset, decoder} + } } return &structDecoder{fields}, nil } diff --git a/jsoniter_reflect_test.go b/jsoniter_reflect_test.go index b6c79e8..1f08071 100644 --- a/jsoniter_reflect_test.go +++ b/jsoniter_reflect_test.go @@ -187,9 +187,34 @@ func Test_reflect_struct_string_ptr(t *testing.T) { t.Fatal(struct_.field1) } if *struct_.field2 != "world" { + fmt.Println(iter.Error) + t.Fatal(struct_.field2) + } +} + + +type StructOfTag struct { + field1 string `json:"field-1"` + field2 string `json:"-"` + field3 int `json:",string"` +} + +func Test_reflect_struct_tag_field(t *testing.T) { + iter := ParseString(`{"field-1": "hello", "field2": "", "field3": "100"}`) + struct_ := StructOfTag{field2: "world"} + iter.Read(&struct_) + if struct_.field1 != "hello" { fmt.Println(iter.Error) t.Fatal(struct_.field1) } + if struct_.field2 != "world" { + fmt.Println(iter.Error) + t.Fatal(struct_.field2) + } + if struct_.field3 != 100 { + fmt.Println(iter.Error) + t.Fatal(struct_.field3) + } } func Test_reflect_slice(t *testing.T) { @@ -235,12 +260,12 @@ func Test_reflect_nested(t *testing.T) { func Benchmark_jsoniter_reflect(b *testing.B) { b.ReportAllocs() for n := 0; n < b.N; n++ { - //iter := ParseString(`{"field1": "hello", "field2": "world"}`) - //struct_ := StructOfString{} - //iter.Read(&struct_) - iter := ParseString(`["hello", "world"]`) - array := make([]string, 0, 1) - iter.Read(&array) + iter := ParseString(`{"field3": "100"}`) + struct_ := StructOfTag{} + iter.Read(&struct_) + //iter := ParseString(`["hello", "world"]`) + //array := make([]string, 0, 1) + //iter.Read(&array) } } @@ -270,9 +295,9 @@ func Benchmark_jsoniter_direct(b *testing.B) { func Benchmark_json_reflect(b *testing.B) { b.ReportAllocs() for n := 0; n < b.N; n++ { - //struct_ := StructOfString{} - //json.Unmarshal([]byte(`{"field1": "hello", "field2": "world"}`), &struct_) - array := make([]string, 0, 2) - json.Unmarshal([]byte(`["hello", "world"]`), &array) + struct_ := StructOfTag{} + json.Unmarshal([]byte(`{"field3": "100"}`), &struct_) + //array := make([]string, 0, 2) + //json.Unmarshal([]byte(`["hello", "world"]`), &array) } } \ No newline at end of file