decoder_util.go raw

   1  package json
   2  
   3  import (
   4  	"bytes"
   5  	"encoding/json"
   6  	"fmt"
   7  	"io"
   8  )
   9  
  10  // DiscardUnknownField discards unknown fields from a decoder body.
  11  // This function is useful while deserializing a JSON body with additional
  12  // unknown information that should be discarded.
  13  func DiscardUnknownField(decoder *json.Decoder) error {
  14  	// This deliberately does not share logic with CollectUnknownField, even
  15  	// though it could, because if we were to delegate to that then we'd incur
  16  	// extra allocations and general memory usage.
  17  	v, err := decoder.Token()
  18  	if err == io.EOF {
  19  		return nil
  20  	}
  21  	if err != nil {
  22  		return err
  23  	}
  24  
  25  	if _, ok := v.(json.Delim); ok {
  26  		for decoder.More() {
  27  			err = DiscardUnknownField(decoder)
  28  		}
  29  		endToken, err := decoder.Token()
  30  		if err != nil {
  31  			return err
  32  		}
  33  		if _, ok := endToken.(json.Delim); !ok {
  34  			return fmt.Errorf("invalid JSON : expected json delimiter, found %T %v",
  35  				endToken, endToken)
  36  		}
  37  	}
  38  
  39  	return nil
  40  }
  41  
  42  // CollectUnknownField grabs the contents of unknown fields from the decoder body
  43  // and returns them as a byte slice. This is useful for skipping unknown fields without
  44  // completely discarding them.
  45  func CollectUnknownField(decoder *json.Decoder) ([]byte, error) {
  46  	result, err := collectUnknownField(decoder)
  47  	if err != nil {
  48  		return nil, err
  49  	}
  50  
  51  	buff := bytes.NewBuffer(nil)
  52  	encoder := json.NewEncoder(buff)
  53  
  54  	if err := encoder.Encode(result); err != nil {
  55  		return nil, err
  56  	}
  57  
  58  	return buff.Bytes(), nil
  59  }
  60  
  61  func collectUnknownField(decoder *json.Decoder) (interface{}, error) {
  62  	// Grab the initial value. This could either be a concrete value like a string or a a
  63  	// delimiter.
  64  	token, err := decoder.Token()
  65  	if err == io.EOF {
  66  		return nil, nil
  67  	}
  68  	if err != nil {
  69  		return nil, err
  70  	}
  71  
  72  	// If it's an array or object, we'll need to recurse.
  73  	delim, ok := token.(json.Delim)
  74  	if ok {
  75  		var result interface{}
  76  		if delim == '{' {
  77  			result, err = collectUnknownObject(decoder)
  78  			if err != nil {
  79  				return nil, err
  80  			}
  81  		} else {
  82  			result, err = collectUnknownArray(decoder)
  83  			if err != nil {
  84  				return nil, err
  85  			}
  86  		}
  87  
  88  		// Discard the closing token. decoder.Token handles checking for matching delimiters
  89  		if _, err := decoder.Token(); err != nil {
  90  			return nil, err
  91  		}
  92  		return result, nil
  93  	}
  94  
  95  	return token, nil
  96  }
  97  
  98  func collectUnknownArray(decoder *json.Decoder) ([]interface{}, error) {
  99  	// We need to create an empty array here instead of a nil array, since by getting
 100  	// into this function at all we necessarily have seen a non-nil list.
 101  	array := []interface{}{}
 102  
 103  	for decoder.More() {
 104  		value, err := collectUnknownField(decoder)
 105  		if err != nil {
 106  			return nil, err
 107  		}
 108  		array = append(array, value)
 109  	}
 110  
 111  	return array, nil
 112  }
 113  
 114  func collectUnknownObject(decoder *json.Decoder) (map[string]interface{}, error) {
 115  	object := make(map[string]interface{})
 116  
 117  	for decoder.More() {
 118  		key, err := collectUnknownField(decoder)
 119  		if err != nil {
 120  			return nil, err
 121  		}
 122  
 123  		// Keys have to be strings, which is particularly important as the encoder
 124  		// won't except a map with interface{} keys
 125  		stringKey, ok := key.(string)
 126  		if !ok {
 127  			return nil, fmt.Errorf("expected string key, found %T", key)
 128  		}
 129  
 130  		value, err := collectUnknownField(decoder)
 131  		if err != nil {
 132  			return nil, err
 133  		}
 134  
 135  		object[stringKey] = value
 136  	}
 137  
 138  	return object, nil
 139  }
 140