@@ -27,13 +27,24 @@ var (
2727 // (numeric) but the Struct field was a non numeric type (i.e. not int, uint,
2828 // float, etc)
2929 ErrUnknownFieldNumberType = errors .New ("The struct field was not of a known number type" )
30- // ErrUnsupportedPtrType is returned when the Struct field was a pointer but
31- // the JSON value was of a different type
32- ErrUnsupportedPtrType = errors .New ("Pointer type in struct is not supported" )
3330 // ErrInvalidType is returned when the given type is incompatible with the expected type.
3431 ErrInvalidType = errors .New ("Invalid type provided" ) // I wish we used punctuation.
3532)
3633
34+ // ErrUnsupportedPtrType is returned when the Struct field was a pointer but
35+ // the JSON value was of a different type
36+ func ErrUnsupportedPtrType (rf reflect.Value , t reflect.Type , structField reflect.StructField ) error {
37+ typeName := t .Elem ().Name ()
38+ kind := t .Elem ().Kind ()
39+ if kind .String () != "" && kind .String () != typeName {
40+ typeName = fmt .Sprintf ("%s (%s)" , typeName , kind .String ())
41+ }
42+ return fmt .Errorf (
43+ "jsonapi: Can't unmarshal %+v (%s) to struct field `%s`, which is a pointer to `%s`" ,
44+ rf , rf .Type ().Kind (), structField .Name , typeName ,
45+ )
46+ }
47+
3748// UnmarshalPayload converts an io into a struct instance using jsonapi tags on
3849// struct fields. This method supports single request payloads only, at the
3950// moment. Bulk creates and updates are not supported yet.
@@ -256,7 +267,8 @@ func unmarshalNode(data *Node, model reflect.Value, included *map[string]*Node)
256267 continue
257268 }
258269
259- value , err := unmarshalAttribute (attribute , args , fieldType .Type , fieldValue )
270+ structField := fieldType
271+ value , err := unmarshalAttribute (attribute , args , structField , fieldValue )
260272 if err != nil {
261273 er = err
262274 break
@@ -363,9 +375,10 @@ func assign(field, value reflect.Value) {
363375 }
364376}
365377
366- func unmarshalAttribute (attribute interface {}, args []string , fieldType reflect.Type , fieldValue reflect.Value ) (value reflect.Value , err error ) {
378+ func unmarshalAttribute (attribute interface {}, args []string , structField reflect.StructField , fieldValue reflect.Value ) (value reflect.Value , err error ) {
367379
368380 value = reflect .ValueOf (attribute )
381+ fieldType := structField .Type
369382
370383 // Handle field of type []string
371384 if fieldValue .Type () == reflect .TypeOf ([]string {}) {
@@ -399,7 +412,7 @@ func unmarshalAttribute(attribute interface{}, args []string, fieldType reflect.
399412
400413 // Field was a Pointer type
401414 if fieldValue .Kind () == reflect .Ptr {
402- value , err = handlePointer (attribute , args , fieldType , fieldValue )
415+ value , err = handlePointer (attribute , args , fieldType , fieldValue , structField )
403416 return
404417 }
405418
@@ -527,7 +540,7 @@ func handleNumeric(attribute interface{}, args []string, fieldType reflect.Type,
527540 return numericValue , nil
528541}
529542
530- func handlePointer (attribute interface {}, args []string , fieldType reflect.Type , fieldValue reflect.Value ) (reflect.Value , error ) {
543+ func handlePointer (attribute interface {}, args []string , fieldType reflect.Type , fieldValue reflect.Value , structField reflect. StructField ) (reflect.Value , error ) {
531544 t := fieldValue .Type ()
532545 var concreteVal reflect.Value
533546
@@ -543,11 +556,11 @@ func handlePointer(attribute interface{}, args []string, fieldType reflect.Type,
543556 case uintptr :
544557 concreteVal = reflect .ValueOf (& cVal )
545558 default :
546- return reflect.Value {}, ErrUnsupportedPtrType
559+ return reflect.Value {}, ErrUnsupportedPtrType ( reflect . ValueOf ( attribute ), fieldType , structField )
547560 }
548561
549562 if t != concreteVal .Type () {
550- return reflect.Value {}, ErrUnsupportedPtrType
563+ return reflect.Value {}, ErrUnsupportedPtrType ( reflect . ValueOf ( attribute ), fieldType , structField )
551564 }
552565
553566 return concreteVal , nil
0 commit comments