Skip to content

Commit

Permalink
Merge pull request #10 from weberr13/set-field-with-unmarshaler
Browse files Browse the repository at this point in the history
Add method to parse underlying type into object
  • Loading branch information
meriburgess authored Oct 23, 2019
2 parents 9c876ee + e800f82 commit edd46d1
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 1 deletion.
19 changes: 19 additions & 0 deletions decode/decode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"fmt"
"io/ioutil"
"testing"
"time"

. "github.com/smartystreets/goconvey/convey"
"github.com/weberr13/go-decode/decode"
Expand Down Expand Up @@ -94,6 +95,11 @@ type LivesInStruct struct {
LivesIn *RequiredBasicTypes
}

type TimedStruct struct {
Name string
UpdateTime *time.Time
}

func MyTestFactory(kind string) (interface{}, error) {
fm := map[string]func() interface{}{
"record": NewRecord,
Expand Down Expand Up @@ -475,4 +481,17 @@ func TestDecodeNestedObject(t *testing.T) {
_, err := decode.UnmarshalJSONInto([]byte(b), &PetOwner{}, SchemaPathFactory)
So(err, ShouldNotBeNil)
})
Convey("Test parsing and decoding with underlying type", t, func() {
b := `{ "name": "john", "updateTime": "2019-10-21T14:56:28.292468-06:00" }`
i, err := decode.UnmarshalJSONInto([]byte(b), &TimedStruct{}, nil)
So(err, ShouldBeNil)
expTime, _ := time.Parse(time.RFC3339, "2019-10-21T14:56:28.292468-06:00")
So(i.(*TimedStruct), ShouldResemble, &TimedStruct{Name: "john", UpdateTime: &expTime})

})
Convey("Test parsing and decoding with incorrect underlying type", t, func() {
b := `{ "name": "john", "updateTime": "string" }`
_, err := decode.UnmarshalJSONInto([]byte(b), &TimedStruct{}, nil)
So(err, ShouldNotBeNil)
})
}
26 changes: 25 additions & 1 deletion decode/decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,11 @@ func DecodeInto(m map[string]interface{}, o interface{}, pf PathFactory) (interf
nV := reflect.New(ft)

if !vV.Type().ConvertibleTo(ft) {
return nil, fmt.Errorf("cannot convert value (%v) to field '%s' type\n", v, fldName)
err := parseAndSetField(fldName, field, nV, vV)
if err != nil {
return nil, err
}
continue
}
nV.Elem().Set(vV.Convert(ft))
field.Set(nV.Elem().Addr())
Expand Down Expand Up @@ -348,3 +352,23 @@ func UnmarshalJSONInto(b []byte, o interface{}, pf PathFactory) (interface{}, er
}
return DecodeInto(m, o, pf)
}

func parseAndSetField(path string, field, newField, val reflect.Value) error {
unmarshaler, ok := newField.Interface().(json.Unmarshaler)
if ok {
// marshal val back to []byte since it was converted to some underlying type (int/string)
valBytes, err := json.Marshal(val.Interface());
if err != nil {
return fmt.Errorf("Cannot convert value to []byte when attempting to set '%s': %s", path, err)
}
// unmarshal valBytes back into newField object via the unmarshaler
err = unmarshaler.UnmarshalJSON(valBytes)
if err != nil {
return fmt.Errorf("Cannot unmarshal byte values for field '%s': %s", path, err)
}
// set field to the value unmarshaled into newField
field.Set(newField)
return nil
}
return fmt.Errorf("cannot convert value (%v) to field '%s' type", val, path)
}

0 comments on commit edd46d1

Please sign in to comment.