mirror of
https://github.com/json-iterator/go.git
synced 2025-04-20 11:28:49 +02:00
support customize reflection
This commit is contained in:
parent
8ef8e04fbc
commit
9873b4d32c
45
json_customize_test.go
Normal file
45
json_customize_test.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package jsoniter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_customize_type_decoder(t *testing.T) {
|
||||||
|
RegisterTypeDecoder("time.Time", func(ptr unsafe.Pointer, iter *Iterator) {
|
||||||
|
t, err := time.ParseInLocation("2006-01-02 15:04:05", iter.ReadString(), time.UTC)
|
||||||
|
if err != nil {
|
||||||
|
iter.Error = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*((*time.Time)(ptr)) = t
|
||||||
|
})
|
||||||
|
defer ClearDecoders()
|
||||||
|
val := time.Time{}
|
||||||
|
err := Unmarshal([]byte(`"2016-12-05 08:43:28"`), &val)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
year, month, day := val.Date()
|
||||||
|
if year != 2016 || month != 12 || day != 5 {
|
||||||
|
t.Fatal(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Tom struct {
|
||||||
|
field1 string
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_customize_field_decoder(t *testing.T) {
|
||||||
|
RegisterFieldDecoder("jsoniter.Tom", "field1", func(ptr unsafe.Pointer, iter *Iterator) {
|
||||||
|
*((*string)(ptr)) = strconv.Itoa(iter.ReadInt())
|
||||||
|
})
|
||||||
|
defer ClearDecoders()
|
||||||
|
tom := Tom{}
|
||||||
|
err := Unmarshal([]byte(`{"field1": 100}`), &tom)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,14 @@
|
|||||||
package jsoniter
|
package jsoniter
|
||||||
|
|
||||||
|
import "io"
|
||||||
|
|
||||||
// adapt to json/encoding api
|
// adapt to json/encoding api
|
||||||
|
|
||||||
func Unmarshal(data []byte, v interface{}) error {
|
func Unmarshal(data []byte, v interface{}) error {
|
||||||
iter := ParseBytes(data)
|
iter := ParseBytes(data)
|
||||||
iter.Read(v)
|
iter.Read(v)
|
||||||
|
if iter.Error == io.EOF {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return iter.Error
|
return iter.Error
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"unsafe"
|
"unsafe"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"strings"
|
"strings"
|
||||||
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Decoder interface {
|
type Decoder interface {
|
||||||
@ -117,12 +118,21 @@ type stringNumberDecoder struct {
|
|||||||
|
|
||||||
func (decoder *stringNumberDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
func (decoder *stringNumberDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||||
c := iter.readByte()
|
c := iter.readByte()
|
||||||
|
if iter.Error != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
if c != '"' {
|
if c != '"' {
|
||||||
iter.ReportError("stringNumberDecoder", `expect "`)
|
iter.ReportError("stringNumberDecoder", `expect "`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
decoder.elemDecoder.decode(ptr, iter)
|
decoder.elemDecoder.decode(ptr, iter)
|
||||||
|
if iter.Error != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
c = iter.readByte()
|
c = iter.readByte()
|
||||||
|
if iter.Error != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
if c != '"' {
|
if c != '"' {
|
||||||
iter.ReportError("stringNumberDecoder", `expect "`)
|
iter.ReportError("stringNumberDecoder", `expect "`)
|
||||||
return
|
return
|
||||||
@ -145,11 +155,12 @@ func (decoder *optionalDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type structDecoder struct {
|
type structDecoder struct {
|
||||||
|
type_ reflect.Type
|
||||||
fields map[string]Decoder
|
fields map[string]Decoder
|
||||||
}
|
}
|
||||||
|
|
||||||
func (decoder *structDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
func (decoder *structDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||||
for field := iter.ReadObject(); field != ""; field = iter.ReadObject() {
|
for field := iter.ReadObject(); field != "" && iter.Error == nil; field = iter.ReadObject() {
|
||||||
fieldDecoder := decoder.fields[field]
|
fieldDecoder := decoder.fields[field]
|
||||||
if fieldDecoder == nil {
|
if fieldDecoder == nil {
|
||||||
iter.Skip()
|
iter.Skip()
|
||||||
@ -157,16 +168,22 @@ func (decoder *structDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
|||||||
fieldDecoder.decode(ptr, iter)
|
fieldDecoder.decode(ptr, iter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if iter.Error != nil && iter.Error != io.EOF {
|
||||||
|
iter.Error = fmt.Errorf("%v: %s", decoder.type_, iter.Error.Error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type structFieldDecoder struct {
|
type structFieldDecoder struct {
|
||||||
offset uintptr
|
field *reflect.StructField
|
||||||
fieldDecoder Decoder
|
fieldDecoder Decoder
|
||||||
}
|
}
|
||||||
|
|
||||||
func (decoder *structFieldDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
func (decoder *structFieldDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||||
fieldPtr := uintptr(ptr) + decoder.offset
|
fieldPtr := uintptr(ptr) + decoder.field.Offset
|
||||||
decoder.fieldDecoder.decode(unsafe.Pointer(fieldPtr), iter)
|
decoder.fieldDecoder.decode(unsafe.Pointer(fieldPtr), iter)
|
||||||
|
if iter.Error != nil && iter.Error != io.EOF {
|
||||||
|
iter.Error = fmt.Errorf("%s: %s", decoder.field.Name, iter.Error.Error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type sliceDecoder struct {
|
type sliceDecoder struct {
|
||||||
@ -185,12 +202,15 @@ type sliceHeader struct {
|
|||||||
func (decoder *sliceDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
func (decoder *sliceDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||||
slice := (*sliceHeader)(ptr)
|
slice := (*sliceHeader)(ptr)
|
||||||
slice.Len = 0
|
slice.Len = 0
|
||||||
for iter.ReadArray() {
|
for iter.ReadArray() && iter.Error == nil {
|
||||||
offset := uintptr(slice.Len) * decoder.elemType.Size()
|
offset := uintptr(slice.Len) * decoder.elemType.Size()
|
||||||
growOne(slice, decoder.sliceType, decoder.elemType)
|
growOne(slice, decoder.sliceType, decoder.elemType)
|
||||||
dataPtr := uintptr(slice.Data) + offset
|
dataPtr := uintptr(slice.Data) + offset
|
||||||
decoder.elemDecoder.decode(unsafe.Pointer(dataPtr), iter)
|
decoder.elemDecoder.decode(unsafe.Pointer(dataPtr), iter)
|
||||||
}
|
}
|
||||||
|
if iter.Error != nil && iter.Error != io.EOF {
|
||||||
|
iter.Error = fmt.Errorf("%v: %s", decoder.sliceType, iter.Error.Error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// grow grows the slice s so that it can hold extra more values, allocating
|
// grow grows the slice s so that it can hold extra more values, allocating
|
||||||
@ -215,8 +235,8 @@ func growOne(slice *sliceHeader, sliceType reflect.Type, elementType reflect.Typ
|
|||||||
}
|
}
|
||||||
dst := unsafe.Pointer(reflect.MakeSlice(sliceType, newLen, newCap).Pointer())
|
dst := unsafe.Pointer(reflect.MakeSlice(sliceType, newLen, newCap).Pointer())
|
||||||
originalBytesCount := uintptr(slice.Len) * elementType.Size()
|
originalBytesCount := uintptr(slice.Len) * elementType.Size()
|
||||||
srcPtr := (*[1<<30]byte)(slice.Data)
|
srcPtr := (*[1 << 30]byte)(slice.Data)
|
||||||
dstPtr := (*[1<<30]byte)(dst)
|
dstPtr := (*[1 << 30]byte)(dst)
|
||||||
for i := uintptr(0); i < originalBytesCount; i++ {
|
for i := uintptr(0); i < originalBytesCount; i++ {
|
||||||
dstPtr[i] = srcPtr[i]
|
dstPtr[i] = srcPtr[i]
|
||||||
}
|
}
|
||||||
@ -247,10 +267,38 @@ func getDecoderFromCache(cacheKey string) Decoder {
|
|||||||
return cache[cacheKey]
|
return cache[cacheKey]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var typeDecoders map[string]Decoder
|
||||||
|
var fieldDecoders map[string]Decoder
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
typeDecoders = map[string]Decoder{}
|
||||||
|
fieldDecoders = map[string]Decoder{}
|
||||||
atomic.StorePointer(&DECODERS, unsafe.Pointer(&map[string]Decoder{}))
|
atomic.StorePointer(&DECODERS, unsafe.Pointer(&map[string]Decoder{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DecoderFunc func(ptr unsafe.Pointer, iter *Iterator)
|
||||||
|
|
||||||
|
type funcDecoder struct {
|
||||||
|
func_ DecoderFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (decoder *funcDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||||
|
decoder.func_(ptr, iter)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterTypeDecoder(type_ string, func_ DecoderFunc) {
|
||||||
|
typeDecoders[type_] = &funcDecoder{func_}
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterFieldDecoder(type_ string, field string, func_ DecoderFunc) {
|
||||||
|
fieldDecoders[fmt.Sprintf("%s/%s", type_, field)] = &funcDecoder{func_}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ClearDecoders() {
|
||||||
|
typeDecoders = map[string]Decoder{}
|
||||||
|
fieldDecoders = map[string]Decoder{}
|
||||||
|
}
|
||||||
|
|
||||||
// emptyInterface is the header for an interface{} value.
|
// emptyInterface is the header for an interface{} value.
|
||||||
type emptyInterface struct {
|
type emptyInterface struct {
|
||||||
typ *struct{}
|
typ *struct{}
|
||||||
@ -293,6 +341,10 @@ func decoderOfType(type_ reflect.Type) (Decoder, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func decoderOfPtr(type_ reflect.Type) (Decoder, error) {
|
func decoderOfPtr(type_ reflect.Type) (Decoder, error) {
|
||||||
|
typeDecoder := typeDecoders[type_.String()]
|
||||||
|
if typeDecoder != nil {
|
||||||
|
return typeDecoder, nil
|
||||||
|
}
|
||||||
switch type_.Kind() {
|
switch type_.Kind() {
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
return &stringDecoder{}, nil
|
return &stringDecoder{}, nil
|
||||||
@ -341,28 +393,32 @@ func decoderOfOptional(type_ reflect.Type) (Decoder, error) {
|
|||||||
return &optionalDecoder{type_, decoder}, nil
|
return &optionalDecoder{type_, decoder}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func decoderOfStruct(type_ reflect.Type) (Decoder, error) {
|
func decoderOfStruct(type_ reflect.Type) (Decoder, error) {
|
||||||
fields := map[string]Decoder{}
|
fields := map[string]Decoder{}
|
||||||
for i := 0; i < type_.NumField(); i++ {
|
for i := 0; i < type_.NumField(); i++ {
|
||||||
field := type_.Field(i)
|
field := type_.Field(i)
|
||||||
|
fieldDecoderKey := fmt.Sprintf("%s/%s", type_.String(), field.Name)
|
||||||
|
decoder := fieldDecoders[fieldDecoderKey]
|
||||||
tagParts := strings.Split(field.Tag.Get("json"), ",")
|
tagParts := strings.Split(field.Tag.Get("json"), ",")
|
||||||
jsonFieldName := tagParts[0]
|
jsonFieldName := tagParts[0]
|
||||||
if jsonFieldName == "" {
|
if jsonFieldName == "" {
|
||||||
jsonFieldName = field.Name
|
jsonFieldName = field.Name
|
||||||
}
|
}
|
||||||
decoder, err := decoderOfPtr(field.Type)
|
if decoder == nil {
|
||||||
|
var err error
|
||||||
|
decoder, err = decoderOfPtr(field.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return prefix(fmt.Sprintf("{%s}", field.Name)).addTo(decoder, err)
|
return prefix(fmt.Sprintf("{%s}", field.Name)).addTo(decoder, err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if len(tagParts) > 1 && tagParts[1] == "string" {
|
if len(tagParts) > 1 && tagParts[1] == "string" {
|
||||||
decoder = &stringNumberDecoder{decoder}
|
decoder = &stringNumberDecoder{decoder}
|
||||||
}
|
}
|
||||||
if jsonFieldName != "-" {
|
if jsonFieldName != "-" {
|
||||||
fields[jsonFieldName] = &structFieldDecoder{field.Offset, decoder}
|
fields[jsonFieldName] = &structFieldDecoder{&field, decoder}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &structDecoder{fields}, nil
|
return &structDecoder{type_, fields}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func decoderOfSlice(type_ reflect.Type) (Decoder, error) {
|
func decoderOfSlice(type_ reflect.Type) (Decoder, error) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user