1// The mapstructure package exposes functionality to convert an 2// abitrary map[string]interface{} into a native Go structure. 3// 4// The Go structure can be arbitrarily complex, containing slices, 5// other structs, etc. and the decoder will properly decode nested 6// maps and so on into the proper structures in the native Go struct. 7// See the examples to see what the decoder is capable of. 8package mapstructure 9 10import ( 11 "errors" 12 "fmt" 13 "reflect" 14 "sort" 15 "strconv" 16 "strings" 17) 18 19// DecodeHookFunc is the callback function that can be used for 20// data transformations. See "DecodeHook" in the DecoderConfig 21// struct. 22type DecodeHookFunc func( 23 from reflect.Kind, 24 to reflect.Kind, 25 data interface{}) (interface{}, error) 26 27// DecoderConfig is the configuration that is used to create a new decoder 28// and allows customization of various aspects of decoding. 29type DecoderConfig struct { 30 // DecodeHook, if set, will be called before any decoding and any 31 // type conversion (if WeaklyTypedInput is on). This lets you modify 32 // the values before they're set down onto the resulting struct. 33 // 34 // If an error is returned, the entire decode will fail with that 35 // error. 36 DecodeHook DecodeHookFunc 37 38 // If ErrorUnused is true, then it is an error for there to exist 39 // keys in the original map that were unused in the decoding process 40 // (extra keys). 41 ErrorUnused bool 42 43 // If WeaklyTypedInput is true, the decoder will make the following 44 // "weak" conversions: 45 // 46 // - bools to string (true = "1", false = "0") 47 // - numbers to string (base 10) 48 // - bools to int/uint (true = 1, false = 0) 49 // - strings to int/uint (base implied by prefix) 50 // - int to bool (true if value != 0) 51 // - string to bool (accepts: 1, t, T, TRUE, true, True, 0, f, F, 52 // FALSE, false, False. Anything else is an error) 53 // - empty array = empty map and vice versa 54 // 55 WeaklyTypedInput bool 56 57 // Metadata is the struct that will contain extra metadata about 58 // the decoding. If this is nil, then no metadata will be tracked. 59 Metadata *Metadata 60 61 // Result is a pointer to the struct that will contain the decoded 62 // value. 63 Result interface{} 64 65 // The tag name that mapstructure reads for field names. This 66 // defaults to "mapstructure" 67 TagName string 68} 69 70// A Decoder takes a raw interface value and turns it into structured 71// data, keeping track of rich error information along the way in case 72// anything goes wrong. Unlike the basic top-level Decode method, you can 73// more finely control how the Decoder behaves using the DecoderConfig 74// structure. The top-level Decode method is just a convenience that sets 75// up the most basic Decoder. 76type Decoder struct { 77 config *DecoderConfig 78} 79 80// Metadata contains information about decoding a structure that 81// is tedious or difficult to get otherwise. 82type Metadata struct { 83 // Keys are the keys of the structure which were successfully decoded 84 Keys []string 85 86 // Unused is a slice of keys that were found in the raw value but 87 // weren't decoded since there was no matching field in the result interface 88 Unused []string 89} 90 91// Decode takes a map and uses reflection to convert it into the 92// given Go native structure. val must be a pointer to a struct. 93func Decode(m interface{}, rawVal interface{}) error { 94 config := &DecoderConfig{ 95 Metadata: nil, 96 Result: rawVal, 97 } 98 99 decoder, err := NewDecoder(config) 100 if err != nil { 101 return err 102 } 103 104 return decoder.Decode(m) 105} 106 107// WeakDecode is the same as Decode but is shorthand to enable 108// WeaklyTypedInput. See DecoderConfig for more info. 109func WeakDecode(input, output interface{}) error { 110 config := &DecoderConfig{ 111 Metadata: nil, 112 Result: output, 113 WeaklyTypedInput: true, 114 } 115 116 decoder, err := NewDecoder(config) 117 if err != nil { 118 return err 119 } 120 121 return decoder.Decode(input) 122} 123 124// NewDecoder returns a new decoder for the given configuration. Once 125// a decoder has been returned, the same configuration must not be used 126// again. 127func NewDecoder(config *DecoderConfig) (*Decoder, error) { 128 val := reflect.ValueOf(config.Result) 129 if val.Kind() != reflect.Ptr { 130 return nil, errors.New("result must be a pointer") 131 } 132 133 val = val.Elem() 134 if !val.CanAddr() { 135 return nil, errors.New("result must be addressable (a pointer)") 136 } 137 138 if config.Metadata != nil { 139 if config.Metadata.Keys == nil { 140 config.Metadata.Keys = make([]string, 0) 141 } 142 143 if config.Metadata.Unused == nil { 144 config.Metadata.Unused = make([]string, 0) 145 } 146 } 147 148 if config.TagName == "" { 149 config.TagName = "mapstructure" 150 } 151 152 result := &Decoder{ 153 config: config, 154 } 155 156 return result, nil 157} 158 159// Decode decodes the given raw interface to the target pointer specified 160// by the configuration. 161func (d *Decoder) Decode(raw interface{}) error { 162 return d.decode("", raw, reflect.ValueOf(d.config.Result).Elem()) 163} 164 165// Decodes an unknown data type into a specific reflection value. 166func (d *Decoder) decode(name string, data interface{}, val reflect.Value) error { 167 if data == nil { 168 // If the data is nil, then we don't set anything. 169 return nil 170 } 171 172 dataVal := reflect.ValueOf(data) 173 if !dataVal.IsValid() { 174 // If the data value is invalid, then we just set the value 175 // to be the zero value. 176 val.Set(reflect.Zero(val.Type())) 177 return nil 178 } 179 180 if d.config.DecodeHook != nil { 181 // We have a DecodeHook, so let's pre-process the data. 182 var err error 183 data, err = d.config.DecodeHook(getKind(dataVal), getKind(val), data) 184 if err != nil { 185 return err 186 } 187 } 188 189 var err error 190 dataKind := getKind(val) 191 switch dataKind { 192 case reflect.Bool: 193 err = d.decodeBool(name, data, val) 194 case reflect.Interface: 195 err = d.decodeBasic(name, data, val) 196 case reflect.String: 197 err = d.decodeString(name, data, val) 198 case reflect.Int: 199 err = d.decodeInt(name, data, val) 200 case reflect.Uint: 201 err = d.decodeUint(name, data, val) 202 case reflect.Float32: 203 err = d.decodeFloat(name, data, val) 204 case reflect.Struct: 205 err = d.decodeStruct(name, data, val) 206 case reflect.Map: 207 err = d.decodeMap(name, data, val) 208 case reflect.Ptr: 209 err = d.decodePtr(name, data, val) 210 case reflect.Slice: 211 err = d.decodeSlice(name, data, val) 212 default: 213 // If we reached this point then we weren't able to decode it 214 return fmt.Errorf("%s: unsupported type: %s", name, dataKind) 215 } 216 217 // If we reached here, then we successfully decoded SOMETHING, so 218 // mark the key as used if we're tracking metadata. 219 if d.config.Metadata != nil && name != "" { 220 d.config.Metadata.Keys = append(d.config.Metadata.Keys, name) 221 } 222 223 return err 224} 225 226// This decodes a basic type (bool, int, string, etc.) and sets the 227// value to "data" of that type. 228func (d *Decoder) decodeBasic(name string, data interface{}, val reflect.Value) error { 229 dataVal := reflect.ValueOf(data) 230 dataValType := dataVal.Type() 231 if !dataValType.AssignableTo(val.Type()) { 232 return fmt.Errorf( 233 "'%s' expected type '%s', got '%s'", 234 name, val.Type(), dataValType) 235 } 236 237 val.Set(dataVal) 238 return nil 239} 240 241func (d *Decoder) decodeString(name string, data interface{}, val reflect.Value) error { 242 dataVal := reflect.ValueOf(data) 243 dataKind := getKind(dataVal) 244 245 converted := true 246 switch { 247 case dataKind == reflect.String: 248 val.SetString(dataVal.String()) 249 case dataKind == reflect.Bool && d.config.WeaklyTypedInput: 250 if dataVal.Bool() { 251 val.SetString("1") 252 } else { 253 val.SetString("0") 254 } 255 case dataKind == reflect.Int && d.config.WeaklyTypedInput: 256 val.SetString(strconv.FormatInt(dataVal.Int(), 10)) 257 case dataKind == reflect.Uint && d.config.WeaklyTypedInput: 258 val.SetString(strconv.FormatUint(dataVal.Uint(), 10)) 259 case dataKind == reflect.Float32 && d.config.WeaklyTypedInput: 260 val.SetString(strconv.FormatFloat(dataVal.Float(), 'f', -1, 64)) 261 case dataKind == reflect.Slice && d.config.WeaklyTypedInput: 262 dataType := dataVal.Type() 263 elemKind := dataType.Elem().Kind() 264 switch { 265 case elemKind == reflect.Uint8: 266 val.SetString(string(dataVal.Interface().([]uint8))) 267 default: 268 converted = false 269 } 270 default: 271 converted = false 272 } 273 274 if !converted { 275 return fmt.Errorf( 276 "'%s' expected type '%s', got unconvertible type '%s'", 277 name, val.Type(), dataVal.Type()) 278 } 279 280 return nil 281} 282 283func (d *Decoder) decodeInt(name string, data interface{}, val reflect.Value) error { 284 dataVal := reflect.ValueOf(data) 285 dataKind := getKind(dataVal) 286 287 switch { 288 case dataKind == reflect.Int: 289 val.SetInt(dataVal.Int()) 290 case dataKind == reflect.Uint: 291 val.SetInt(int64(dataVal.Uint())) 292 case dataKind == reflect.Float32: 293 val.SetInt(int64(dataVal.Float())) 294 case dataKind == reflect.Bool && d.config.WeaklyTypedInput: 295 if dataVal.Bool() { 296 val.SetInt(1) 297 } else { 298 val.SetInt(0) 299 } 300 case dataKind == reflect.String && d.config.WeaklyTypedInput: 301 i, err := strconv.ParseInt(dataVal.String(), 0, val.Type().Bits()) 302 if err == nil { 303 val.SetInt(i) 304 } else { 305 return fmt.Errorf("cannot parse '%s' as int: %s", name, err) 306 } 307 default: 308 return fmt.Errorf( 309 "'%s' expected type '%s', got unconvertible type '%s'", 310 name, val.Type(), dataVal.Type()) 311 } 312 313 return nil 314} 315 316func (d *Decoder) decodeUint(name string, data interface{}, val reflect.Value) error { 317 dataVal := reflect.ValueOf(data) 318 dataKind := getKind(dataVal) 319 320 switch { 321 case dataKind == reflect.Int: 322 val.SetUint(uint64(dataVal.Int())) 323 case dataKind == reflect.Uint: 324 val.SetUint(dataVal.Uint()) 325 case dataKind == reflect.Float32: 326 val.SetUint(uint64(dataVal.Float())) 327 case dataKind == reflect.Bool && d.config.WeaklyTypedInput: 328 if dataVal.Bool() { 329 val.SetUint(1) 330 } else { 331 val.SetUint(0) 332 } 333 case dataKind == reflect.String && d.config.WeaklyTypedInput: 334 i, err := strconv.ParseUint(dataVal.String(), 0, val.Type().Bits()) 335 if err == nil { 336 val.SetUint(i) 337 } else { 338 return fmt.Errorf("cannot parse '%s' as uint: %s", name, err) 339 } 340 default: 341 return fmt.Errorf( 342 "'%s' expected type '%s', got unconvertible type '%s'", 343 name, val.Type(), dataVal.Type()) 344 } 345 346 return nil 347} 348 349func (d *Decoder) decodeBool(name string, data interface{}, val reflect.Value) error { 350 dataVal := reflect.ValueOf(data) 351 dataKind := getKind(dataVal) 352 353 switch { 354 case dataKind == reflect.Bool: 355 val.SetBool(dataVal.Bool()) 356 case dataKind == reflect.Int && d.config.WeaklyTypedInput: 357 val.SetBool(dataVal.Int() != 0) 358 case dataKind == reflect.Uint && d.config.WeaklyTypedInput: 359 val.SetBool(dataVal.Uint() != 0) 360 case dataKind == reflect.Float32 && d.config.WeaklyTypedInput: 361 val.SetBool(dataVal.Float() != 0) 362 case dataKind == reflect.String && d.config.WeaklyTypedInput: 363 b, err := strconv.ParseBool(dataVal.String()) 364 if err == nil { 365 val.SetBool(b) 366 } else if dataVal.String() == "" { 367 val.SetBool(false) 368 } else { 369 return fmt.Errorf("cannot parse '%s' as bool: %s", name, err) 370 } 371 default: 372 return fmt.Errorf( 373 "'%s' expected type '%s', got unconvertible type '%s'", 374 name, val.Type(), dataVal.Type()) 375 } 376 377 return nil 378} 379 380func (d *Decoder) decodeFloat(name string, data interface{}, val reflect.Value) error { 381 dataVal := reflect.ValueOf(data) 382 dataKind := getKind(dataVal) 383 384 switch { 385 case dataKind == reflect.Int: 386 val.SetFloat(float64(dataVal.Int())) 387 case dataKind == reflect.Uint: 388 val.SetFloat(float64(dataVal.Uint())) 389 case dataKind == reflect.Float32: 390 val.SetFloat(float64(dataVal.Float())) 391 case dataKind == reflect.Bool && d.config.WeaklyTypedInput: 392 if dataVal.Bool() { 393 val.SetFloat(1) 394 } else { 395 val.SetFloat(0) 396 } 397 case dataKind == reflect.String && d.config.WeaklyTypedInput: 398 f, err := strconv.ParseFloat(dataVal.String(), val.Type().Bits()) 399 if err == nil { 400 val.SetFloat(f) 401 } else { 402 return fmt.Errorf("cannot parse '%s' as float: %s", name, err) 403 } 404 default: 405 return fmt.Errorf( 406 "'%s' expected type '%s', got unconvertible type '%s'", 407 name, val.Type(), dataVal.Type()) 408 } 409 410 return nil 411} 412 413func (d *Decoder) decodeMap(name string, data interface{}, val reflect.Value) error { 414 valType := val.Type() 415 valKeyType := valType.Key() 416 valElemType := valType.Elem() 417 418 // Make a new map to hold our result 419 mapType := reflect.MapOf(valKeyType, valElemType) 420 valMap := reflect.MakeMap(mapType) 421 422 // Check input type 423 dataVal := reflect.Indirect(reflect.ValueOf(data)) 424 if dataVal.Kind() != reflect.Map { 425 // Accept empty array/slice instead of an empty map in weakly typed mode 426 if d.config.WeaklyTypedInput && 427 (dataVal.Kind() == reflect.Slice || dataVal.Kind() == reflect.Array) && 428 dataVal.Len() == 0 { 429 val.Set(valMap) 430 return nil 431 } else { 432 return fmt.Errorf("'%s' expected a map, got '%s'", name, dataVal.Kind()) 433 } 434 } 435 436 // Accumulate errors 437 errors := make([]string, 0) 438 439 for _, k := range dataVal.MapKeys() { 440 fieldName := fmt.Sprintf("%s[%s]", name, k) 441 442 // First decode the key into the proper type 443 currentKey := reflect.Indirect(reflect.New(valKeyType)) 444 if err := d.decode(fieldName, k.Interface(), currentKey); err != nil { 445 errors = appendErrors(errors, err) 446 continue 447 } 448 449 // Next decode the data into the proper type 450 v := dataVal.MapIndex(k).Interface() 451 currentVal := reflect.Indirect(reflect.New(valElemType)) 452 if err := d.decode(fieldName, v, currentVal); err != nil { 453 errors = appendErrors(errors, err) 454 continue 455 } 456 457 valMap.SetMapIndex(currentKey, currentVal) 458 } 459 460 // Set the built up map to the value 461 val.Set(valMap) 462 463 // If we had errors, return those 464 if len(errors) > 0 { 465 return &Error{errors} 466 } 467 468 return nil 469} 470 471func (d *Decoder) decodePtr(name string, data interface{}, val reflect.Value) error { 472 // Create an element of the concrete (non pointer) type and decode 473 // into that. Then set the value of the pointer to this type. 474 valType := val.Type() 475 valElemType := valType.Elem() 476 realVal := reflect.New(valElemType) 477 if err := d.decode(name, data, reflect.Indirect(realVal)); err != nil { 478 return err 479 } 480 481 val.Set(realVal) 482 return nil 483} 484 485func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value) error { 486 dataVal := reflect.Indirect(reflect.ValueOf(data)) 487 dataValKind := dataVal.Kind() 488 valType := val.Type() 489 valElemType := valType.Elem() 490 sliceType := reflect.SliceOf(valElemType) 491 492 // Check input type 493 if dataValKind != reflect.Array && dataValKind != reflect.Slice { 494 // Accept empty map instead of array/slice in weakly typed mode 495 if d.config.WeaklyTypedInput && dataVal.Kind() == reflect.Map && dataVal.Len() == 0 { 496 val.Set(reflect.MakeSlice(sliceType, 0, 0)) 497 return nil 498 } else { 499 return fmt.Errorf( 500 "'%s': source data must be an array or slice, got %s", name, dataValKind) 501 } 502 } 503 504 // Make a new slice to hold our result, same size as the original data. 505 valSlice := reflect.MakeSlice(sliceType, dataVal.Len(), dataVal.Len()) 506 507 // Accumulate any errors 508 errors := make([]string, 0) 509 510 for i := 0; i < dataVal.Len(); i++ { 511 currentData := dataVal.Index(i).Interface() 512 currentField := valSlice.Index(i) 513 514 fieldName := fmt.Sprintf("%s[%d]", name, i) 515 if err := d.decode(fieldName, currentData, currentField); err != nil { 516 errors = appendErrors(errors, err) 517 } 518 } 519 520 // Finally, set the value to the slice we built up 521 val.Set(valSlice) 522 523 // If there were errors, we return those 524 if len(errors) > 0 { 525 return &Error{errors} 526 } 527 528 return nil 529} 530 531func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value) error { 532 dataVal := reflect.Indirect(reflect.ValueOf(data)) 533 dataValKind := dataVal.Kind() 534 if dataValKind != reflect.Map { 535 return fmt.Errorf("'%s' expected a map, got '%s'", name, dataValKind) 536 } 537 538 dataValType := dataVal.Type() 539 if kind := dataValType.Key().Kind(); kind != reflect.String && kind != reflect.Interface { 540 return fmt.Errorf( 541 "'%s' needs a map with string keys, has '%s' keys", 542 name, dataValType.Key().Kind()) 543 } 544 545 dataValKeys := make(map[reflect.Value]struct{}) 546 dataValKeysUnused := make(map[interface{}]struct{}) 547 for _, dataValKey := range dataVal.MapKeys() { 548 dataValKeys[dataValKey] = struct{}{} 549 dataValKeysUnused[dataValKey.Interface()] = struct{}{} 550 } 551 552 errors := make([]string, 0) 553 554 // This slice will keep track of all the structs we'll be decoding. 555 // There can be more than one struct if there are embedded structs 556 // that are squashed. 557 structs := make([]reflect.Value, 1, 5) 558 structs[0] = val 559 560 // Compile the list of all the fields that we're going to be decoding 561 // from all the structs. 562 fields := make(map[*reflect.StructField]reflect.Value) 563 for len(structs) > 0 { 564 structVal := structs[0] 565 structs = structs[1:] 566 567 structType := structVal.Type() 568 for i := 0; i < structType.NumField(); i++ { 569 fieldType := structType.Field(i) 570 571 if fieldType.Anonymous { 572 fieldKind := fieldType.Type.Kind() 573 if fieldKind != reflect.Struct { 574 errors = appendErrors(errors, 575 fmt.Errorf("%s: unsupported type: %s", fieldType.Name, fieldKind)) 576 continue 577 } 578 579 // We have an embedded field. We "squash" the fields down 580 // if specified in the tag. 581 squash := false 582 tagParts := strings.Split(fieldType.Tag.Get(d.config.TagName), ",") 583 for _, tag := range tagParts[1:] { 584 if tag == "squash" { 585 squash = true 586 break 587 } 588 } 589 590 if squash { 591 structs = append(structs, val.FieldByName(fieldType.Name)) 592 continue 593 } 594 } 595 596 // Normal struct field, store it away 597 fields[&fieldType] = structVal.Field(i) 598 } 599 } 600 601 for fieldType, field := range fields { 602 fieldName := fieldType.Name 603 604 tagValue := fieldType.Tag.Get(d.config.TagName) 605 tagValue = strings.SplitN(tagValue, ",", 2)[0] 606 if tagValue != "" { 607 fieldName = tagValue 608 } 609 610 rawMapKey := reflect.ValueOf(fieldName) 611 rawMapVal := dataVal.MapIndex(rawMapKey) 612 if !rawMapVal.IsValid() { 613 // Do a slower search by iterating over each key and 614 // doing case-insensitive search. 615 for dataValKey, _ := range dataValKeys { 616 mK, ok := dataValKey.Interface().(string) 617 if !ok { 618 // Not a string key 619 continue 620 } 621 622 if strings.EqualFold(mK, fieldName) { 623 rawMapKey = dataValKey 624 rawMapVal = dataVal.MapIndex(dataValKey) 625 break 626 } 627 } 628 629 if !rawMapVal.IsValid() { 630 // There was no matching key in the map for the value in 631 // the struct. Just ignore. 632 continue 633 } 634 } 635 636 // Delete the key we're using from the unused map so we stop tracking 637 delete(dataValKeysUnused, rawMapKey.Interface()) 638 639 if !field.IsValid() { 640 // This should never happen 641 panic("field is not valid") 642 } 643 644 // If we can't set the field, then it is unexported or something, 645 // and we just continue onwards. 646 if !field.CanSet() { 647 continue 648 } 649 650 // If the name is empty string, then we're at the root, and we 651 // don't dot-join the fields. 652 if name != "" { 653 fieldName = fmt.Sprintf("%s.%s", name, fieldName) 654 } 655 656 if err := d.decode(fieldName, rawMapVal.Interface(), field); err != nil { 657 errors = appendErrors(errors, err) 658 } 659 } 660 661 if d.config.ErrorUnused && len(dataValKeysUnused) > 0 { 662 keys := make([]string, 0, len(dataValKeysUnused)) 663 for rawKey, _ := range dataValKeysUnused { 664 keys = append(keys, rawKey.(string)) 665 } 666 sort.Strings(keys) 667 668 err := fmt.Errorf("'%s' has invalid keys: %s", name, strings.Join(keys, ", ")) 669 errors = appendErrors(errors, err) 670 } 671 672 if len(errors) > 0 { 673 return &Error{errors} 674 } 675 676 // Add the unused keys to the list of unused keys if we're tracking metadata 677 if d.config.Metadata != nil { 678 for rawKey, _ := range dataValKeysUnused { 679 key := rawKey.(string) 680 if name != "" { 681 key = fmt.Sprintf("%s.%s", name, key) 682 } 683 684 d.config.Metadata.Unused = append(d.config.Metadata.Unused, key) 685 } 686 } 687 688 return nil 689} 690 691func getKind(val reflect.Value) reflect.Kind { 692 kind := val.Kind() 693 694 switch { 695 case kind >= reflect.Int && kind <= reflect.Int64: 696 return reflect.Int 697 case kind >= reflect.Uint && kind <= reflect.Uint64: 698 return reflect.Uint 699 case kind >= reflect.Float32 && kind <= reflect.Float64: 700 return reflect.Float32 701 default: 702 return kind 703 } 704} 705