Recognize TextUnmarshaler and use it

This change recognizes TextUnmarshaler during object mapping, and
will defer to it when we have a string but are assigning to a
non-string target that implements the interface.
This commit is contained in:
joeduffy 2017-02-26 11:51:38 -08:00
parent 2f60a414c7
commit 1bdd24395c

View file

@ -3,6 +3,7 @@
package mapper package mapper
import ( import (
"encoding"
"fmt" "fmt"
"reflect" "reflect"
"strings" "strings"
@ -161,6 +162,7 @@ func (md *mapper) DecodeField(tree Object, ty reflect.Type, key string, target i
} }
var emptyObject map[string]interface{} var emptyObject map[string]interface{}
var textUnmarshalerType = reflect.TypeOf(new(encoding.TextUnmarshaler)).Elem()
// adjustValue converts if possible to produce the target type. // adjustValue converts if possible to produce the target type.
func (md *mapper) adjustValue(val reflect.Value, to reflect.Type, ty reflect.Type, key string) (reflect.Value, error) { func (md *mapper) adjustValue(val reflect.Value, to reflect.Type, ty reflect.Type, key string) (reflect.Value, error) {
@ -264,6 +266,18 @@ func (md *mapper) adjustValue(val reflect.Value, to reflect.Type, ty reflect.Typ
return val, fmt.Errorf( return val, fmt.Errorf(
"Cannot decode Object to type %v; it isn't a struct, and no custom decoder exists", to) "Cannot decode Object to type %v; it isn't a struct, and no custom decoder exists", to)
} }
} else if val.Type().Kind() == reflect.String {
// If the source is a string, see if the target implements encoding.TextUnmarshaler.
target := reflect.New(to)
if target.Type().Implements(textUnmarshalerType) {
um := target.Interface().(encoding.TextUnmarshaler)
if err := um.UnmarshalText([]byte(val.String())); err != nil {
return val, err
}
val = target.Elem()
} else {
break
}
} else { } else {
break break
} }