...

Source file src/github.com/go-openapi/swag/json.go

Documentation: github.com/go-openapi/swag

     1  // Copyright 2015 go-swagger maintainers
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package swag
    16  
    17  import (
    18  	"bytes"
    19  	"encoding/json"
    20  	"log"
    21  	"reflect"
    22  	"strings"
    23  	"sync"
    24  
    25  	"github.com/mailru/easyjson/jlexer"
    26  	"github.com/mailru/easyjson/jwriter"
    27  )
    28  
    29  // nullJSON represents a JSON object with null type
    30  var nullJSON = []byte("null")
    31  
    32  // DefaultJSONNameProvider the default cache for types
    33  var DefaultJSONNameProvider = NewNameProvider()
    34  
    35  const comma = byte(',')
    36  
    37  var closers map[byte]byte
    38  
    39  func init() {
    40  	closers = map[byte]byte{
    41  		'{': '}',
    42  		'[': ']',
    43  	}
    44  }
    45  
    46  type ejMarshaler interface {
    47  	MarshalEasyJSON(w *jwriter.Writer)
    48  }
    49  
    50  type ejUnmarshaler interface {
    51  	UnmarshalEasyJSON(w *jlexer.Lexer)
    52  }
    53  
    54  // WriteJSON writes json data, prefers finding an appropriate interface to short-circuit the marshaler
    55  // so it takes the fastest option available.
    56  func WriteJSON(data interface{}) ([]byte, error) {
    57  	if d, ok := data.(ejMarshaler); ok {
    58  		jw := new(jwriter.Writer)
    59  		d.MarshalEasyJSON(jw)
    60  		return jw.BuildBytes()
    61  	}
    62  	if d, ok := data.(json.Marshaler); ok {
    63  		return d.MarshalJSON()
    64  	}
    65  	return json.Marshal(data)
    66  }
    67  
    68  // ReadJSON reads json data, prefers finding an appropriate interface to short-circuit the unmarshaler
    69  // so it takes the fastest option available
    70  func ReadJSON(data []byte, value interface{}) error {
    71  	trimmedData := bytes.Trim(data, "\x00")
    72  	if d, ok := value.(ejUnmarshaler); ok {
    73  		jl := &jlexer.Lexer{Data: trimmedData}
    74  		d.UnmarshalEasyJSON(jl)
    75  		return jl.Error()
    76  	}
    77  	if d, ok := value.(json.Unmarshaler); ok {
    78  		return d.UnmarshalJSON(trimmedData)
    79  	}
    80  	return json.Unmarshal(trimmedData, value)
    81  }
    82  
    83  // DynamicJSONToStruct converts an untyped json structure into a struct
    84  func DynamicJSONToStruct(data interface{}, target interface{}) error {
    85  	// TODO: convert straight to a json typed map  (mergo + iterate?)
    86  	b, err := WriteJSON(data)
    87  	if err != nil {
    88  		return err
    89  	}
    90  	return ReadJSON(b, target)
    91  }
    92  
    93  // ConcatJSON concatenates multiple json objects efficiently
    94  func ConcatJSON(blobs ...[]byte) []byte {
    95  	if len(blobs) == 0 {
    96  		return nil
    97  	}
    98  
    99  	last := len(blobs) - 1
   100  	for blobs[last] == nil || bytes.Equal(blobs[last], nullJSON) {
   101  		// strips trailing null objects
   102  		last--
   103  		if last < 0 {
   104  			// there was nothing but "null"s or nil...
   105  			return nil
   106  		}
   107  	}
   108  	if last == 0 {
   109  		return blobs[0]
   110  	}
   111  
   112  	var opening, closing byte
   113  	var idx, a int
   114  	buf := bytes.NewBuffer(nil)
   115  
   116  	for i, b := range blobs[:last+1] {
   117  		if b == nil || bytes.Equal(b, nullJSON) {
   118  			// a null object is in the list: skip it
   119  			continue
   120  		}
   121  		if len(b) > 0 && opening == 0 { // is this an array or an object?
   122  			opening, closing = b[0], closers[b[0]]
   123  		}
   124  
   125  		if opening != '{' && opening != '[' {
   126  			continue // don't know how to concatenate non container objects
   127  		}
   128  
   129  		if len(b) < 3 { // yep empty but also the last one, so closing this thing
   130  			if i == last && a > 0 {
   131  				if err := buf.WriteByte(closing); err != nil {
   132  					log.Println(err)
   133  				}
   134  			}
   135  			continue
   136  		}
   137  
   138  		idx = 0
   139  		if a > 0 { // we need to join with a comma for everything beyond the first non-empty item
   140  			if err := buf.WriteByte(comma); err != nil {
   141  				log.Println(err)
   142  			}
   143  			idx = 1 // this is not the first or the last so we want to drop the leading bracket
   144  		}
   145  
   146  		if i != last { // not the last one, strip brackets
   147  			if _, err := buf.Write(b[idx : len(b)-1]); err != nil {
   148  				log.Println(err)
   149  			}
   150  		} else { // last one, strip only the leading bracket
   151  			if _, err := buf.Write(b[idx:]); err != nil {
   152  				log.Println(err)
   153  			}
   154  		}
   155  		a++
   156  	}
   157  	// somehow it ended up being empty, so provide a default value
   158  	if buf.Len() == 0 {
   159  		if err := buf.WriteByte(opening); err != nil {
   160  			log.Println(err)
   161  		}
   162  		if err := buf.WriteByte(closing); err != nil {
   163  			log.Println(err)
   164  		}
   165  	}
   166  	return buf.Bytes()
   167  }
   168  
   169  // ToDynamicJSON turns an object into a properly JSON typed structure
   170  func ToDynamicJSON(data interface{}) interface{} {
   171  	// TODO: convert straight to a json typed map (mergo + iterate?)
   172  	b, err := json.Marshal(data)
   173  	if err != nil {
   174  		log.Println(err)
   175  	}
   176  	var res interface{}
   177  	if err := json.Unmarshal(b, &res); err != nil {
   178  		log.Println(err)
   179  	}
   180  	return res
   181  }
   182  
   183  // FromDynamicJSON turns an object into a properly JSON typed structure
   184  func FromDynamicJSON(data, target interface{}) error {
   185  	b, err := json.Marshal(data)
   186  	if err != nil {
   187  		log.Println(err)
   188  	}
   189  	return json.Unmarshal(b, target)
   190  }
   191  
   192  // NameProvider represents an object capable of translating from go property names
   193  // to json property names
   194  // This type is thread-safe.
   195  type NameProvider struct {
   196  	lock  *sync.Mutex
   197  	index map[reflect.Type]nameIndex
   198  }
   199  
   200  type nameIndex struct {
   201  	jsonNames map[string]string
   202  	goNames   map[string]string
   203  }
   204  
   205  // NewNameProvider creates a new name provider
   206  func NewNameProvider() *NameProvider {
   207  	return &NameProvider{
   208  		lock:  &sync.Mutex{},
   209  		index: make(map[reflect.Type]nameIndex),
   210  	}
   211  }
   212  
   213  func buildnameIndex(tpe reflect.Type, idx, reverseIdx map[string]string) {
   214  	for i := 0; i < tpe.NumField(); i++ {
   215  		targetDes := tpe.Field(i)
   216  
   217  		if targetDes.PkgPath != "" { // unexported
   218  			continue
   219  		}
   220  
   221  		if targetDes.Anonymous { // walk embedded structures tree down first
   222  			buildnameIndex(targetDes.Type, idx, reverseIdx)
   223  			continue
   224  		}
   225  
   226  		if tag := targetDes.Tag.Get("json"); tag != "" {
   227  
   228  			parts := strings.Split(tag, ",")
   229  			if len(parts) == 0 {
   230  				continue
   231  			}
   232  
   233  			nm := parts[0]
   234  			if nm == "-" {
   235  				continue
   236  			}
   237  			if nm == "" { // empty string means we want to use the Go name
   238  				nm = targetDes.Name
   239  			}
   240  
   241  			idx[nm] = targetDes.Name
   242  			reverseIdx[targetDes.Name] = nm
   243  		}
   244  	}
   245  }
   246  
   247  func newNameIndex(tpe reflect.Type) nameIndex {
   248  	var idx = make(map[string]string, tpe.NumField())
   249  	var reverseIdx = make(map[string]string, tpe.NumField())
   250  
   251  	buildnameIndex(tpe, idx, reverseIdx)
   252  	return nameIndex{jsonNames: idx, goNames: reverseIdx}
   253  }
   254  
   255  // GetJSONNames gets all the json property names for a type
   256  func (n *NameProvider) GetJSONNames(subject interface{}) []string {
   257  	n.lock.Lock()
   258  	defer n.lock.Unlock()
   259  	tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
   260  	names, ok := n.index[tpe]
   261  	if !ok {
   262  		names = n.makeNameIndex(tpe)
   263  	}
   264  
   265  	res := make([]string, 0, len(names.jsonNames))
   266  	for k := range names.jsonNames {
   267  		res = append(res, k)
   268  	}
   269  	return res
   270  }
   271  
   272  // GetJSONName gets the json name for a go property name
   273  func (n *NameProvider) GetJSONName(subject interface{}, name string) (string, bool) {
   274  	tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
   275  	return n.GetJSONNameForType(tpe, name)
   276  }
   277  
   278  // GetJSONNameForType gets the json name for a go property name on a given type
   279  func (n *NameProvider) GetJSONNameForType(tpe reflect.Type, name string) (string, bool) {
   280  	n.lock.Lock()
   281  	defer n.lock.Unlock()
   282  	names, ok := n.index[tpe]
   283  	if !ok {
   284  		names = n.makeNameIndex(tpe)
   285  	}
   286  	nme, ok := names.goNames[name]
   287  	return nme, ok
   288  }
   289  
   290  func (n *NameProvider) makeNameIndex(tpe reflect.Type) nameIndex {
   291  	names := newNameIndex(tpe)
   292  	n.index[tpe] = names
   293  	return names
   294  }
   295  
   296  // GetGoName gets the go name for a json property name
   297  func (n *NameProvider) GetGoName(subject interface{}, name string) (string, bool) {
   298  	tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
   299  	return n.GetGoNameForType(tpe, name)
   300  }
   301  
   302  // GetGoNameForType gets the go name for a given type for a json property name
   303  func (n *NameProvider) GetGoNameForType(tpe reflect.Type, name string) (string, bool) {
   304  	n.lock.Lock()
   305  	defer n.lock.Unlock()
   306  	names, ok := n.index[tpe]
   307  	if !ok {
   308  		names = n.makeNameIndex(tpe)
   309  	}
   310  	nme, ok := names.jsonNames[name]
   311  	return nme, ok
   312  }
   313  

View as plain text