Skip to content

Commit

Permalink
Merge pull request #44 from RangelReale/text-unmarshal
Browse files Browse the repository at this point in the history
Form reader support for encoding.TextUnmarshaler
  • Loading branch information
qiangxue committed Dec 25, 2017
2 parents 4d40027 + aa09cd1 commit efb54ad
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 0 deletions.
29 changes: 29 additions & 0 deletions reader.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package routing

import (
"encoding"
"encoding/json"
"encoding/xml"
"errors"
Expand All @@ -19,6 +20,10 @@ const (
MIME_MULTIPART_FORM = "multipart/form-data"
)

var (
textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
)

// DataReader is used by Context.Read() to read data from an HTTP request.
type DataReader interface {
// Read reads from the given HTTP request and populate the specified data.
Expand Down Expand Up @@ -107,6 +112,13 @@ func readForm(form map[string][]string, prefix string, rv reflect.Value) error {
name = prefix + "." + name
}

// check if type implements a known type, like encoding.TextUnmarshaler
if ok, err := readFormFieldKnownType(form, name, rv.Field(i)); err != nil {
return err
} else if ok {
continue
}

if ft.Kind() != reflect.Struct {
if err := readFormField(form, name, rv.Field(i)); err != nil {
return err
Expand All @@ -124,6 +136,23 @@ func readForm(form map[string][]string, prefix string, rv reflect.Value) error {
return nil
}

func readFormFieldKnownType(form map[string][]string, name string, rv reflect.Value) (bool, error) {
value, ok := form[name]
if !ok {
return false, nil
}
rv = indirect(rv)
rt := rv.Type()

// check if type implements encoding.TextUnmarshaler
if rt.Implements(textUnmarshalerType) {
return true, rv.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(value[0]))
} else if reflect.PtrTo(rt).Implements(textUnmarshalerType) {
return true, rv.Addr().Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(value[0]))
}
return false, nil
}

func readFormField(form map[string][]string, name string, rv reflect.Value) error {
value, ok := form[name]
if !ok {
Expand Down
24 changes: 24 additions & 0 deletions reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,27 @@ func TestDefaultDataReader(t *testing.T) {
assert.Equal(t, expected, data, test.tag)
}
}

type TU struct {
UValue string
}

func (tu *TU) UnmarshalText(text []byte) error {
tu.UValue = "TU_" + string(text[:])
return nil
}

func TestTextUnmarshaler(t *testing.T) {
var a struct {
ATU TU `form:"atu"`
NTU string `form:"ntu"`
}
values := map[string][]string{
"atu": []string{"ORIGINAL"},
"ntu": []string{"ORIGINAL"},
}
err := ReadFormData(values, &a)
assert.Nil(t, err)
assert.Equal(t, "TU_ORIGINAL", a.ATU.UValue)
assert.Equal(t, "ORIGINAL", a.NTU)
}

0 comments on commit efb54ad

Please sign in to comment.