瀏覽代碼

support recursive type

Tao Wen 8 年之前
父節點
當前提交
91b9e828b7
共有 4 個文件被更改,包括 71 次插入6 次删除
  1. 55 4
      feature_reflect.go
  2. 1 1
      feature_reflect_array.go
  3. 1 1
      feature_reflect_object.go
  4. 14 0
      jsoniter_reflect_struct_test.go

+ 55 - 4
feature_reflect.go

@@ -181,7 +181,6 @@ func (decoder *optionalDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
 }
 
 type optionalEncoder struct {
-	valueType    reflect.Type
 	valueEncoder Encoder
 }
 
@@ -205,6 +204,30 @@ func (encoder *optionalEncoder) isEmpty(ptr unsafe.Pointer) bool {
 	}
 }
 
+type placeholderEncoder struct {
+	valueEncoder Encoder
+}
+
+func (encoder *placeholderEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
+	encoder.valueEncoder.encode(ptr, stream)
+}
+
+func (encoder *placeholderEncoder) encodeInterface(val interface{}, stream *Stream) {
+	WriteToStream(val, stream, encoder)
+}
+
+func (encoder *placeholderEncoder) isEmpty(ptr unsafe.Pointer) bool {
+	return encoder.valueEncoder.isEmpty(ptr)
+}
+
+type placeholderDecoder struct {
+	valueDecoder Decoder
+}
+
+func (decoder *placeholderDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
+	decoder.valueDecoder.decode(ptr, iter)
+}
+
 type mapDecoder struct {
 	mapType      reflect.Type
 	elemType     reflect.Type
@@ -374,6 +397,20 @@ func decoderOfType(typ reflect.Type) (Decoder, error) {
 	if typeDecoder != nil {
 		return typeDecoder, nil
 	}
+	cacheKey := typ
+	cachedDecoder := getDecoderFromCache(cacheKey)
+	if cachedDecoder != nil {
+		return cachedDecoder, nil
+	}
+	placeholder := &placeholderDecoder{}
+	addDecoderToCache(cacheKey, placeholder)
+	newDecoder, err := createDecoderOfType(typ)
+	placeholder.valueDecoder = newDecoder
+	addDecoderToCache(cacheKey, newDecoder)
+	return newDecoder, err
+}
+
+func createDecoderOfType(typ reflect.Type) (Decoder, error) {
 	switch typ.Kind() {
 	case reflect.String:
 		return &stringCodec{}, nil
@@ -410,7 +447,7 @@ func decoderOfType(typ reflect.Type) (Decoder, error) {
 			return nil, errors.New("unsupportd type: " + typ.String())
 		}
 	case reflect.Struct:
-		return prefix(fmt.Sprintf("[%s]", typeName)).addToDecoder(decoderOfStruct(typ))
+		return prefix(fmt.Sprintf("[%s]", typ.String())).addToDecoder(decoderOfStruct(typ))
 	case reflect.Slice:
 		return prefix("[slice]").addToDecoder(decoderOfSlice(typ))
 	case reflect.Map:
@@ -431,6 +468,20 @@ func encoderOfType(typ reflect.Type) (Encoder, error) {
 	if typeEncoder != nil {
 		return typeEncoder, nil
 	}
+	cacheKey := typ
+	cachedEncoder := getEncoderFromCache(cacheKey)
+	if cachedEncoder != nil {
+		return cachedEncoder, nil
+	}
+	placeholder := &placeholderEncoder{}
+	addEncoderToCache(cacheKey, placeholder)
+	newEncoder, err := createEncoderOfType(typ)
+	placeholder.valueEncoder = newEncoder
+	addEncoderToCache(cacheKey, newEncoder)
+	return newEncoder, err
+}
+
+func createEncoderOfType(typ reflect.Type) (Encoder, error) {
 	switch typ.Kind() {
 	case reflect.String:
 		return &stringCodec{}, nil
@@ -463,7 +514,7 @@ func encoderOfType(typ reflect.Type) (Encoder, error) {
 	case reflect.Interface:
 		return &interfaceCodec{}, nil
 	case reflect.Struct:
-		return prefix(fmt.Sprintf("[%s]", typeName)).addToEncoder(encoderOfStruct(typ))
+		return prefix(fmt.Sprintf("[%s]", typ.String())).addToEncoder(encoderOfStruct(typ))
 	case reflect.Slice:
 		return prefix("[slice]").addToEncoder(encoderOfSlice(typ))
 	case reflect.Map:
@@ -490,7 +541,7 @@ func encoderOfOptional(typ reflect.Type) (Encoder, error) {
 	if err != nil {
 		return nil, err
 	}
-	return &optionalEncoder{elemType, decoder}, nil
+	return &optionalEncoder{ decoder}, nil
 }
 
 func decoderOfMap(typ reflect.Type) (Decoder, error) {

+ 1 - 1
feature_reflect_array.go

@@ -21,7 +21,7 @@ func encoderOfSlice(typ reflect.Type) (Encoder, error) {
 		return nil, err
 	}
 	if typ.Elem().Kind() == reflect.Map {
-		encoder = &optionalEncoder{typ.Elem(), encoder}
+		encoder = &optionalEncoder{ encoder}
 	}
 	return &sliceEncoder{typ, typ.Elem(), encoder}, nil
 }

+ 1 - 1
feature_reflect_object.go

@@ -49,7 +49,7 @@ func encoderOfStruct(typ reflect.Type) (Encoder, error) {
 			// map is stored as pointer in the struct
 			// but if struct only has one map, it is inlined
 			if field.Type.Kind() == reflect.Map && typ.NumField() > 1 {
-				encoder = &optionalEncoder{field.Type, encoder}
+				encoder = &optionalEncoder{encoder}
 			}
 		}
 		for _, fieldName := range fieldNames {

+ 14 - 0
jsoniter_reflect_struct_test.go

@@ -186,3 +186,17 @@ func Test_any_within_struct(t *testing.T) {
 	should.Equal("hello", obj.Field1.ToString())
 	should.Equal("[1,2,3]", obj.Field2.ToString())
 }
+
+func Test_recursive_struct(t *testing.T) {
+	should := require.New(t)
+	type TestObject struct {
+		Field1 string
+		Me *TestObject
+	}
+	obj := TestObject{}
+	str, err := MarshalToString(obj)
+	should.Nil(err)
+	should.Equal(`{"Field1":"","Me":null}`, str)
+	err = UnmarshalFromString(str, &obj)
+	should.Nil(err)
+}