...

Source file src/github.com/aws/smithy-go/document/json/encoder.go

Documentation: github.com/aws/smithy-go/document/json

     1  package json
     2  
     3  import (
     4  	"fmt"
     5  	"math/big"
     6  	"reflect"
     7  
     8  	"github.com/aws/smithy-go/document"
     9  	"github.com/aws/smithy-go/document/internal/serde"
    10  	smithyjson "github.com/aws/smithy-go/encoding/json"
    11  )
    12  
    13  // EncoderOptions is the set of options that can be configured for an Encoder.
    14  type EncoderOptions struct{}
    15  
    16  // Encoder is a Smithy document decoder for JSON based protocols.
    17  type Encoder struct {
    18  	options EncoderOptions
    19  }
    20  
    21  // Encode returns the JSON encoding of v.
    22  func (e *Encoder) Encode(v interface{}) ([]byte, error) {
    23  	encoder := smithyjson.NewEncoder()
    24  
    25  	if err := e.encode(jsonValueProvider(encoder.Value), reflect.ValueOf(v), serde.Tag{}); err != nil {
    26  		return nil, err
    27  	}
    28  
    29  	encodedBytes := encoder.Bytes()
    30  
    31  	if len(encodedBytes) == 0 {
    32  		return nil, nil
    33  	}
    34  
    35  	return encodedBytes, nil
    36  }
    37  
    38  // valueProvider is an interface for retrieving a JSON Value type used for encoding.
    39  type valueProvider interface {
    40  	GetValue() smithyjson.Value
    41  }
    42  
    43  // jsonValueProvider is a valueProvider that returns the JSON value encoder as is.
    44  type jsonValueProvider smithyjson.Value
    45  
    46  func (p jsonValueProvider) GetValue() smithyjson.Value {
    47  	return smithyjson.Value(p)
    48  }
    49  
    50  // jsonObjectKeyProvider is a valueProvider that returns a JSON value type for encoding a value for the given JSON object
    51  // key.
    52  type jsonObjectKeyProvider struct {
    53  	Object *smithyjson.Object
    54  	Key    string
    55  }
    56  
    57  func (p jsonObjectKeyProvider) GetValue() smithyjson.Value {
    58  	return p.Object.Key(p.Key)
    59  }
    60  
    61  // jsonArrayProvider is a valueProvider that returns a JSON value type for encoding a value in the given JSON array.
    62  type jsonArrayProvider struct {
    63  	Array *smithyjson.Array
    64  }
    65  
    66  func (p jsonArrayProvider) GetValue() smithyjson.Value {
    67  	return p.Array.Value()
    68  }
    69  
    70  func (e *Encoder) encode(vp valueProvider, rv reflect.Value, tag serde.Tag) error {
    71  	// Zero values are serialized as null, or skipped if omitEmpty.
    72  	if serde.IsZeroValue(rv) {
    73  		if tag.OmitEmpty {
    74  			return nil
    75  		}
    76  		return e.encodeZeroValue(vp, rv)
    77  	}
    78  
    79  	// Handle both pointers and interface conversion into types
    80  	rv = serde.ValueElem(rv)
    81  
    82  	switch rv.Kind() {
    83  	case reflect.Invalid:
    84  		if tag.OmitEmpty {
    85  			return nil
    86  		}
    87  		vp.GetValue().Null()
    88  		return nil
    89  
    90  	case reflect.Struct:
    91  		return e.encodeStruct(vp, rv)
    92  
    93  	case reflect.Map:
    94  		return e.encodeMap(vp, rv)
    95  
    96  	case reflect.Slice, reflect.Array:
    97  		return e.encodeSlice(vp, rv)
    98  
    99  	case reflect.Chan, reflect.Func, reflect.UnsafePointer:
   100  		// skip unsupported types
   101  		return nil
   102  
   103  	default:
   104  		return e.encodeScalar(vp, rv)
   105  	}
   106  }
   107  
   108  func (e *Encoder) encodeZeroValue(vp valueProvider, rv reflect.Value) error {
   109  	switch rv.Kind() {
   110  	case reflect.Invalid:
   111  		vp.GetValue().Null()
   112  	case reflect.Array:
   113  		vp.GetValue().Array().Close()
   114  	case reflect.Map, reflect.Slice:
   115  		vp.GetValue().Null()
   116  	case reflect.String:
   117  		vp.GetValue().String("")
   118  	case reflect.Bool:
   119  		vp.GetValue().Boolean(false)
   120  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   121  		vp.GetValue().Long(0)
   122  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
   123  		vp.GetValue().ULong(0)
   124  	case reflect.Float32, reflect.Float64:
   125  		vp.GetValue().Double(0)
   126  	case reflect.Interface, reflect.Ptr:
   127  		vp.GetValue().Null()
   128  	default:
   129  		return &document.InvalidMarshalError{Message: fmt.Sprintf("unknown value type: %s", rv.String())}
   130  	}
   131  
   132  	return nil
   133  }
   134  
   135  func (e *Encoder) encodeStruct(vp valueProvider, rv reflect.Value) error {
   136  	if rv.CanInterface() && document.IsNoSerde(rv.Interface()) {
   137  		return &document.UnmarshalTypeError{
   138  			Value: fmt.Sprintf("unsupported type"),
   139  			Type:  rv.Type(),
   140  		}
   141  	}
   142  
   143  	switch {
   144  	case rv.Type().ConvertibleTo(serde.ReflectTypeOf.Time):
   145  		return &document.InvalidMarshalError{
   146  			Message: fmt.Sprintf("unsupported type %s", rv.Type().String()),
   147  		}
   148  	case rv.Type().ConvertibleTo(serde.ReflectTypeOf.BigFloat):
   149  		fallthrough
   150  	case rv.Type().ConvertibleTo(serde.ReflectTypeOf.BigInt):
   151  		return e.encodeNumber(vp, rv)
   152  	}
   153  
   154  	object := vp.GetValue().Object()
   155  	defer object.Close()
   156  
   157  	fields := serde.GetStructFields(rv.Type())
   158  	for _, f := range fields.All() {
   159  		if f.Name == "" {
   160  			return &document.InvalidMarshalError{Message: "map key cannot be empty"}
   161  		}
   162  
   163  		fv, found := serde.EncoderFieldByIndex(rv, f.Index)
   164  		if !found {
   165  			continue
   166  		}
   167  
   168  		err := e.encode(jsonObjectKeyProvider{
   169  			Object: object,
   170  			Key:    f.Name,
   171  		}, fv, f.Tag)
   172  		if err != nil {
   173  			return err
   174  		}
   175  	}
   176  
   177  	return nil
   178  }
   179  
   180  func (e *Encoder) encodeMap(vp valueProvider, rv reflect.Value) error {
   181  	object := vp.GetValue().Object()
   182  	defer object.Close()
   183  
   184  	for _, key := range rv.MapKeys() {
   185  		keyName := fmt.Sprint(key.Interface())
   186  		if keyName == "" {
   187  			return &document.InvalidMarshalError{Message: "map key cannot be empty"}
   188  		}
   189  
   190  		ev := rv.MapIndex(key)
   191  		err := e.encode(jsonObjectKeyProvider{
   192  			Object: object,
   193  			Key:    keyName,
   194  		}, ev, serde.Tag{})
   195  		if err != nil {
   196  			return err
   197  		}
   198  	}
   199  
   200  	return nil
   201  }
   202  
   203  func (e *Encoder) encodeSlice(value valueProvider, rv reflect.Value) error {
   204  	array := value.GetValue().Array()
   205  	defer array.Close()
   206  
   207  	for i := 0; i < rv.Len(); i++ {
   208  		err := e.encode(jsonArrayProvider{Array: array}, rv.Index(i), serde.Tag{})
   209  		if err != nil {
   210  			return err
   211  		}
   212  	}
   213  
   214  	return nil
   215  }
   216  
   217  func (e *Encoder) encodeScalar(vp valueProvider, rv reflect.Value) error {
   218  	if rv.Type() == serde.ReflectTypeOf.DocumentNumber {
   219  		number := rv.Interface().(document.Number)
   220  		if !isValidJSONNumber(number.String()) {
   221  			return &document.InvalidMarshalError{Message: fmt.Sprintf("invalid number literal: %s", number)}
   222  		}
   223  		vp.GetValue().Write([]byte(number))
   224  	}
   225  
   226  	switch rv.Kind() {
   227  	case reflect.Bool:
   228  		vp.GetValue().Boolean(rv.Bool())
   229  	case reflect.String:
   230  		vp.GetValue().String(rv.String())
   231  	default:
   232  		// Fallback to encoding numbers, will return invalid type if not supported
   233  		err := e.encodeNumber(vp, rv)
   234  		if err != nil {
   235  			return err
   236  		}
   237  	}
   238  
   239  	return nil
   240  }
   241  
   242  func (e *Encoder) encodeNumber(vp valueProvider, rv reflect.Value) error {
   243  	switch rv.Kind() {
   244  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   245  		vp.GetValue().Long(rv.Int())
   246  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   247  		vp.GetValue().ULong(rv.Uint())
   248  	case reflect.Float32:
   249  		vp.GetValue().Float(float32(rv.Float()))
   250  	case reflect.Float64:
   251  		vp.GetValue().Double(rv.Float())
   252  	default:
   253  		rvt := rv.Type()
   254  		switch {
   255  		case rvt.ConvertibleTo(serde.ReflectTypeOf.BigInt):
   256  			bi := rv.Convert(serde.ReflectTypeOf.BigInt).Interface().(big.Int)
   257  			vp.GetValue().BigInteger(&bi)
   258  		case rvt.ConvertibleTo(serde.ReflectTypeOf.BigFloat):
   259  			bf := rv.Convert(serde.ReflectTypeOf.BigFloat).Interface().(big.Float)
   260  			vp.GetValue().BigDecimal(&bf)
   261  		default:
   262  			return &document.InvalidMarshalError{Message: fmt.Sprintf("incompatible type: %s", rvt.String())}
   263  		}
   264  	}
   265  
   266  	return nil
   267  }
   268  
   269  // isValidJSONNumber reports whether s is a valid JSON number literal.
   270  // From https://golang.org/src/encoding/json/encode.go#L652 isValidNumber
   271  // Copyright 2010 The Go Authors.
   272  func isValidJSONNumber(s string) bool {
   273  	// This function implements the JSON numbers grammar.
   274  	// See https://tools.ietf.org/html/rfc7159#section-6
   275  	// and https://www.json.org/img/number.png
   276  
   277  	if s == "" {
   278  		return false
   279  	}
   280  
   281  	// Optional -
   282  	if s[0] == '-' {
   283  		s = s[1:]
   284  		if s == "" {
   285  			return false
   286  		}
   287  	}
   288  
   289  	// Digits
   290  	switch {
   291  	default:
   292  		return false
   293  
   294  	case s[0] == '0':
   295  		s = s[1:]
   296  
   297  	case '1' <= s[0] && s[0] <= '9':
   298  		s = s[1:]
   299  		for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
   300  			s = s[1:]
   301  		}
   302  	}
   303  
   304  	// . followed by 1 or more digits.
   305  	if len(s) >= 2 && s[0] == '.' && '0' <= s[1] && s[1] <= '9' {
   306  		s = s[2:]
   307  		for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
   308  			s = s[1:]
   309  		}
   310  	}
   311  
   312  	// e or E followed by an optional - or + and
   313  	// 1 or more digits.
   314  	if len(s) >= 2 && (s[0] == 'e' || s[0] == 'E') {
   315  		s = s[1:]
   316  		if s[0] == '+' || s[0] == '-' {
   317  			s = s[1:]
   318  			if s == "" {
   319  				return false
   320  			}
   321  		}
   322  		for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
   323  			s = s[1:]
   324  		}
   325  	}
   326  
   327  	// Make sure we are at the end.
   328  	return s == ""
   329  }

View as plain text