From 7da3fd67614a102c60f8e91624c36c24d2e6bf21 Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Tue, 16 May 2017 09:22:18 -0700 Subject: [PATCH 1/3] Show type for ErrUnsupportedPtrType This may aid in figuring out where the problematic JSON is Before: ``` Pointer type in struct is not supported ``` After: ``` Pointer (*int) in struct is not supported ``` --- request.go | 13 ++++++++----- request_test.go | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/request.go b/request.go index fe29706..29361b3 100644 --- a/request.go +++ b/request.go @@ -27,13 +27,16 @@ var ( // (numeric) but the Struct field was a non numeric type (i.e. not int, uint, // float, etc) ErrUnknownFieldNumberType = errors.New("The struct field was not of a known number type") - // ErrUnsupportedPtrType is returned when the Struct field was a pointer but - // the JSON value was of a different type - ErrUnsupportedPtrType = errors.New("Pointer type in struct is not supported") // ErrInvalidType is returned when the given type is incompatible with the expected type. ErrInvalidType = errors.New("Invalid type provided") // I wish we used punctuation. ) +// ErrUnsupportedPtrType is returned when the Struct field was a pointer but +// the JSON value was of a different type +func ErrUnsupportedPtrType(t interface{}) error { + return fmt.Errorf("Pointer (%s) in struct is not supported", t) +} + // UnmarshalPayload converts an io into a struct instance using jsonapi tags on // struct fields. This method supports single request payloads only, at the // moment. Bulk creates and updates are not supported yet. @@ -434,11 +437,11 @@ func unmarshalNode(data *Node, model reflect.Value, included *map[string]*Node) case uintptr: concreteVal = reflect.ValueOf(&cVal) default: - return ErrUnsupportedPtrType + return ErrUnsupportedPtrType(cVal) } if fieldValue.Type() != concreteVal.Type() { - return ErrUnsupportedPtrType + return ErrUnsupportedPtrType(fieldValue.Type()) } fieldValue.Set(concreteVal) diff --git a/request_test.go b/request_test.go index 2206449..efaf4fb 100644 --- a/request_test.go +++ b/request_test.go @@ -126,7 +126,7 @@ func TestUnmarshalToStructWithPointerAttr_BadType(t *testing.T) { in := map[string]interface{}{ "name": true, // This is the wrong type. } - expectedErrorMessage := ErrUnsupportedPtrType.Error() + expectedErrorMessage := ErrUnsupportedPtrType("*string").Error() err := UnmarshalPayload(sampleWithPointerPayload(in), out) From 2259d65ded915208c0ce27068f218e8e8a45c7ee Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Tue, 16 Jan 2018 17:44:28 -0800 Subject: [PATCH 2/3] Add even more info E.g.: ``` [jsonapi unmarshalNode]: Can't unmarshal map[min_containers:2 max_containers:5] () to struct field `Scaling`, which is a pointer to `Scaling` (struct), which is not a supported type ``` --- request.go | 12 +++++++----- request_test.go | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/request.go b/request.go index 29361b3..2179423 100644 --- a/request.go +++ b/request.go @@ -33,8 +33,11 @@ var ( // ErrUnsupportedPtrType is returned when the Struct field was a pointer but // the JSON value was of a different type -func ErrUnsupportedPtrType(t interface{}) error { - return fmt.Errorf("Pointer (%s) in struct is not supported", t) +func ErrUnsupportedPtrType(rf reflect.Value, f reflect.StructField) error { + return fmt.Errorf( + "[jsonapi unmarshalNode]: Can't unmarshal %+v (%s) to struct field `%s`, which is a pointer to `%s` (%s), which is not a supported type", + rf, rf.Type().Name(), f.Name, f.Type.Elem().Name(), f.Type.Elem().Kind(), + ) } // UnmarshalPayload converts an io into a struct instance using jsonapi tags on @@ -424,7 +427,6 @@ func unmarshalNode(data *Node, model reflect.Value, included *map[string]*Node) // Field was a Pointer type if fieldValue.Kind() == reflect.Ptr { var concreteVal reflect.Value - switch cVal := val.(type) { case string: concreteVal = reflect.ValueOf(&cVal) @@ -437,11 +439,11 @@ func unmarshalNode(data *Node, model reflect.Value, included *map[string]*Node) case uintptr: concreteVal = reflect.ValueOf(&cVal) default: - return ErrUnsupportedPtrType(cVal) + return ErrUnsupportedPtrType(reflect.ValueOf(val), fieldType) } if fieldValue.Type() != concreteVal.Type() { - return ErrUnsupportedPtrType(fieldValue.Type()) + return ErrUnsupportedPtrType(reflect.ValueOf(val), fieldType) } fieldValue.Set(concreteVal) diff --git a/request_test.go b/request_test.go index efaf4fb..9fc2961 100644 --- a/request_test.go +++ b/request_test.go @@ -126,7 +126,7 @@ func TestUnmarshalToStructWithPointerAttr_BadType(t *testing.T) { in := map[string]interface{}{ "name": true, // This is the wrong type. } - expectedErrorMessage := ErrUnsupportedPtrType("*string").Error() + expectedErrorMessage := "[jsonapi unmarshalNode]: Can't unmarshal true (bool) to struct field `Name`, which is a pointer to `string` (string), which is not a supported type" err := UnmarshalPayload(sampleWithPointerPayload(in), out) From 42eec26c1b6a69028c192b672398b3501299ce8b Mon Sep 17 00:00:00 2001 From: Marc Abramowitz Date: Wed, 17 Jan 2018 10:26:12 -0800 Subject: [PATCH 3/3] Don't print type & kind if redundant --- request.go | 9 +++++++-- request_test.go | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/request.go b/request.go index 2179423..3b3583b 100644 --- a/request.go +++ b/request.go @@ -34,9 +34,14 @@ var ( // ErrUnsupportedPtrType is returned when the Struct field was a pointer but // the JSON value was of a different type func ErrUnsupportedPtrType(rf reflect.Value, f reflect.StructField) error { + typeName := f.Type.Elem().Name() + kind := f.Type.Elem().Kind() + if kind.String() != "" && kind.String() != typeName { + typeName = fmt.Sprintf("%s (%s)", typeName, kind.String()) + } return fmt.Errorf( - "[jsonapi unmarshalNode]: Can't unmarshal %+v (%s) to struct field `%s`, which is a pointer to `%s` (%s), which is not a supported type", - rf, rf.Type().Name(), f.Name, f.Type.Elem().Name(), f.Type.Elem().Kind(), + "[jsonapi]: Can't unmarshal %+v (%s) to struct field `%s`, which is a pointer to `%s`, which is not a supported type", + rf, rf.Type().Name(), f.Name, typeName, ) } diff --git a/request_test.go b/request_test.go index 9fc2961..fbdef0b 100644 --- a/request_test.go +++ b/request_test.go @@ -126,7 +126,7 @@ func TestUnmarshalToStructWithPointerAttr_BadType(t *testing.T) { in := map[string]interface{}{ "name": true, // This is the wrong type. } - expectedErrorMessage := "[jsonapi unmarshalNode]: Can't unmarshal true (bool) to struct field `Name`, which is a pointer to `string` (string), which is not a supported type" + expectedErrorMessage := "[jsonapi]: Can't unmarshal true (bool) to struct field `Name`, which is a pointer to `string`, which is not a supported type" err := UnmarshalPayload(sampleWithPointerPayload(in), out)