github.com/mundipagg/tracer-splunk-writer@v1.0.6/json/encoder/struct.go (about)

     1  package encoder
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"os"
     7  	"reflect"
     8  	"strings"
     9  	"unsafe"
    10  
    11  	jsoniter "github.com/json-iterator/go"
    12  )
    13  
    14  type Struct struct {
    15  	Type     reflect.Type
    16  	Strategy func(string) string
    17  }
    18  
    19  func (changer *Struct) IsEmpty(ptr unsafe.Pointer) bool {
    20  	return false
    21  }
    22  
    23  func (changer *Struct) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
    24  	beforeBuffer := stream.Buffer()
    25  	defer func() {
    26  		err := recover()
    27  		if err != nil {
    28  			fmt.Fprintf(os.Stderr, "a error occurred while serialization of '%v', error: '%v'", changer.Type.Name(), err)
    29  			stream.SetBuffer(beforeBuffer)
    30  		}
    31  	}()
    32  	v := reflect.NewAt(changer.Type, ptr).Elem()
    33  	switch value := v.Interface().(type) {
    34  	case json.Marshaler:
    35  		valueJ, _ := value.MarshalJSON()
    36  		var valueM interface{}
    37  		_ = json.Unmarshal(valueJ, &valueM)
    38  		stream.WriteVal(valueM)
    39  	case error:
    40  		stream.WriteString(value.Error())
    41  	default:
    42  		stream.WriteObjectStart()
    43  		numFields := v.NumField()
    44  		if numFields > 0 {
    45  			var i int
    46  			for i = 0; i < numFields; i++ {
    47  				fv := v.Field(i)
    48  				ft := changer.Type.Field(i)
    49  				if changer.writeField(ft, fv, stream, false) {
    50  					break
    51  				}
    52  			}
    53  			i++
    54  			for ; i < numFields; i++ {
    55  				fv := v.Field(i)
    56  				ft := changer.Type.Field(i)
    57  				changer.writeField(ft, fv, stream, true)
    58  			}
    59  		}
    60  		stream.WriteObjectEnd()
    61  	}
    62  }
    63  
    64  func (changer *Struct) writeField(structField reflect.StructField, value reflect.Value, stream *jsoniter.Stream, needsComma bool) bool {
    65  	if !value.CanInterface() {
    66  		return false
    67  	}
    68  
    69  	tag := strings.TrimSpace(structField.Tag.Get("json"))
    70  
    71  	if len(tag) == 0 {
    72  		if needsComma {
    73  			stream.WriteMore()
    74  		}
    75  		stream.WriteObjectField(changer.Strategy(structField.Name))
    76  		stream.WriteVal(value.Interface())
    77  
    78  	} else {
    79  		pieces := strings.Split(tag, ",")
    80  		if len(pieces) > 1 {
    81  			if pieces[1] == "omitempty" {
    82  				isZero := func() (isZero bool) {
    83  					defer func() {
    84  						if recover() != nil {
    85  							isZero = false
    86  						}
    87  					}()
    88  					return reflect.DeepEqual(value.Interface(), reflect.Zero(value.Type()).Interface())
    89  				}()
    90  				isNil := func() (isNil bool) {
    91  					defer func() {
    92  						if recover() != nil {
    93  							isNil = false
    94  						}
    95  					}()
    96  					return value.IsNil()
    97  				}()
    98  				if isNil || isZero {
    99  					return false
   100  				}
   101  			}
   102  		}
   103  
   104  		if pieces[0] == "-" {
   105  			return false
   106  		}
   107  
   108  		if needsComma {
   109  			stream.WriteMore()
   110  		}
   111  		stream.WriteObjectField(changer.Strategy(pieces[0]))
   112  		stream.WriteVal(value.Interface())
   113  	}
   114  	return true
   115  }