diff --git a/unmarshal.go b/unmarshal.go index bd9f215..16caddb 100644 --- a/unmarshal.go +++ b/unmarshal.go @@ -77,7 +77,12 @@ func Unmarshal(data []byte, v interface{}) (err error) { value = parseStructureType(result, field.Type()) } else { // set field value depend on it's data type - value = parseDataType(result, field.Kind().String()) + value = parseDataType(result, field.Type().String()) + } + + // maybe it is a custom type, use json.unmarshal + if value == nil { + value = unmarshalGeneric(result.Raw, field) } if v != nil { @@ -130,3 +135,12 @@ func unmarshalStruct(raw string, field reflect.Type) interface{} { return reflect.Indirect(reflect.ValueOf(v)).Interface() } + +func unmarshalGeneric(raw string, field reflect.Value) interface{} { + err := json.Unmarshal([]byte(raw), field.Addr().Interface()) + if err != nil { + panic(err) + } + + return reflect.Indirect(field).Interface() +} diff --git a/unmarshal_test.go b/unmarshal_test.go index d665ead..04b9c76 100644 --- a/unmarshal_test.go +++ b/unmarshal_test.go @@ -1,13 +1,110 @@ package njson import ( + "encoding/json" json2 "encoding/json" + "fmt" "testing" "time" "github.com/google/go-cmp/cmp" ) +type CustomType string +type CustomUnmarshalerType string + +// Implements Unmarshaler +func (ct *CustomUnmarshalerType) UnmarshalJSON(data []byte) error { + var s string + if err := json.Unmarshal(data, &s); err != nil { + return err + } + // add a mark to control it later + *ct = CustomUnmarshalerType(fmt.Sprintf("unmarshaler:%s", s)) + return nil +} + +func TestCustomTypeUnmarshal(t *testing.T) { + + type CustomStruct struct { + Normal string `njson:"inner.nested"` + Custom CustomType `njson:"custom"` + } + + json := `{"custom": "value", "inner": { "nested": "nestedValue"}}` + + var actual CustomStruct + + if err := Unmarshal([]byte(json), &actual); err != nil { + t.Errorf("error should be nil: %v", err) + } + + expected := CustomStruct{ + Normal: "nestedValue", + Custom: CustomType("value"), + } + + diff := cmp.Diff(expected, actual) + + if diff != "" { + t.Errorf(diff) + } +} + +func TestCustomTypeUnmarshaler(t *testing.T) { + + type CustomStruct struct { + Normal string `njson:"inner.nested"` + Custom CustomUnmarshalerType `njson:"custom"` + } + + json := `{"custom": "value", "inner": { "nested": "nestedValue"}}` + + var actual CustomStruct + + if err := Unmarshal([]byte(json), &actual); err != nil { + t.Errorf("error should be nil: %v", err) + } + + expected := CustomStruct{ + Normal: "nestedValue", + Custom: CustomUnmarshalerType("unmarshaler:value"), + } + + diff := cmp.Diff(expected, actual) + + if diff != "" { + t.Errorf(diff) + } +} + +func TestCustomTypeUnmarshalerNested(t *testing.T) { + + type CustomStruct struct { + Normal string `njson:"inner.nested"` + Custom CustomUnmarshalerType `njson:"custom.key.nested"` + } + + json := `{"custom": { "key": {"nested": "value"} }, "inner": { "nested": "nestedValue"}}` + + var actual CustomStruct + + if err := Unmarshal([]byte(json), &actual); err != nil { + t.Errorf("error should be nil: %v", err) + } + + expected := CustomStruct{ + Normal: "nestedValue", + Custom: CustomUnmarshalerType("unmarshaler:value"), + } + + diff := cmp.Diff(expected, actual) + + if diff != "" { + t.Errorf(diff) + } +} + func TestUnmarshalInvalidJson(t *testing.T) { json := ` BAD JSON %% @