From ec5ed7978a82d69334c89741d7dfbe1298165a08 Mon Sep 17 00:00:00 2001 From: Erik Dubbelboer Date: Tue, 4 Feb 2020 13:31:24 +0100 Subject: [PATCH] Fix pointers to alias types This commit fixes pointers to type aliases which are currently not supported. The new test cases will fail with: jsonapi: Can't unmarshal foo (string) to struct field `String`, which is a pointer to `StringType (string)` One other method to fix this when you are able to modify your types is: type StringType = string This is the new (since Go 1.9) way to declare type aliasses which treats the types differently when using reflect. See: https://github.com/golang/example/tree/master/gotypes#named-types --- models_test.go | 13 ++++++++----- request.go | 2 +- request_test.go | 29 +++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/models_test.go b/models_test.go index 2d4aae4..0ce9f4a 100644 --- a/models_test.go +++ b/models_test.go @@ -5,6 +5,8 @@ import ( "time" ) +type StringType string + type BadModel struct { ID int `jsonapi:"primary"` } @@ -18,11 +20,12 @@ type ModelBadTypes struct { } type WithPointer struct { - ID *uint64 `jsonapi:"primary,with-pointers"` - Name *string `jsonapi:"attr,name"` - IsActive *bool `jsonapi:"attr,is-active"` - IntVal *int `jsonapi:"attr,int-val"` - FloatVal *float32 `jsonapi:"attr,float-val"` + ID *uint64 `jsonapi:"primary,with-pointers"` + Name *string `jsonapi:"attr,name"` + IsActive *bool `jsonapi:"attr,is-active"` + IntVal *int `jsonapi:"attr,int-val"` + FloatVal *float32 `jsonapi:"attr,float-val"` + StringVal *StringType `jsonapi:"attr,string-val"` } type Timestamp struct { diff --git a/request.go b/request.go index a7bb0b1..929af34 100644 --- a/request.go +++ b/request.go @@ -580,7 +580,7 @@ func handlePointer( reflect.ValueOf(attribute), fieldType, structField) } - if t != concreteVal.Type() { + if !t.ConvertibleTo(concreteVal.Type()) { return reflect.Value{}, newErrUnsupportedPtrType( reflect.ValueOf(attribute), fieldType, structField) } diff --git a/request_test.go b/request_test.go index 3326598..1a30d57 100644 --- a/request_test.go +++ b/request_test.go @@ -45,6 +45,32 @@ func TestUnmarshall_attrStringSlice(t *testing.T) { } } +func TestUnmarshalToStructWithPointerToNamedType(t *testing.T) { + out := new(WithPointer) + in := map[string]interface{}{ + "string-val": "foo", + } + if err := UnmarshalPayload(sampleWithPointerPayload(in), out); err != nil { + t.Fatal(err) + } + if *out.StringVal != "foo" { + t.Fatalf("Error unmarshalling to string alias ptr") + } +} + +func TestUnmarshalToStructWithPointerToNamedTypeNull(t *testing.T) { + out := new(WithPointer) + in := map[string]interface{}{ + "string-val": nil, + } + if err := UnmarshalPayload(sampleWithPointerPayload(in), out); err != nil { + t.Fatal(err) + } + if out.StringVal != nil { + t.Fatalf("Error unmarshalling to string alias ptr") + } +} + func TestUnmarshalToStructWithPointerAttr(t *testing.T) { out := new(WithPointer) in := map[string]interface{}{ @@ -68,6 +94,9 @@ func TestUnmarshalToStructWithPointerAttr(t *testing.T) { if *out.FloatVal != 1.1 { t.Fatalf("Error unmarshalling to float ptr") } + if out.StringVal != nil { + t.Fatalf("Error unmarshalling to string alias ptr") + } } func TestUnmarshalPayload_ptrsAllNil(t *testing.T) {