Skip to content
This repository was archived by the owner on Sep 4, 2025. It is now read-only.

Commit 8b7e0bc

Browse files
authored
Merge pull request #5 from Slemgrim/refactor-ptr-error
Refactor ptr error and cleanup
2 parents e428b86 + d490a0f commit 8b7e0bc

File tree

2 files changed

+82
-34
lines changed

2 files changed

+82
-34
lines changed

request.go

Lines changed: 70 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -29,22 +29,33 @@ var (
2929
ErrUnknownFieldNumberType = errors.New("The struct field was not of a known number type")
3030
// ErrInvalidType is returned when the given type is incompatible with the expected type.
3131
ErrInvalidType = errors.New("Invalid type provided") // I wish we used punctuation.
32+
3233
)
3334

3435
// ErrUnsupportedPtrType is returned when the Struct field was a pointer but
3536
// 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()
37+
type ErrUnsupportedPtrType struct {
38+
rf reflect.Value
39+
t reflect.Type
40+
structField reflect.StructField
41+
}
42+
43+
func (eupt ErrUnsupportedPtrType) Error() string {
44+
typeName := eupt.t.Elem().Name()
45+
kind := eupt.t.Elem().Kind()
3946
if kind.String() != "" && kind.String() != typeName {
4047
typeName = fmt.Sprintf("%s (%s)", typeName, kind.String())
4148
}
42-
return fmt.Errorf(
49+
return fmt.Sprintf(
4350
"jsonapi: Can't unmarshal %+v (%s) to struct field `%s`, which is a pointer to `%s`",
44-
rf, rf.Type().Kind(), structField.Name, typeName,
51+
eupt.rf, eupt.rf.Type().Kind(), eupt.structField.Name, typeName,
4552
)
4653
}
4754

55+
func newErrUnsupportedPtrType(rf reflect.Value, t reflect.Type, structField reflect.StructField) error {
56+
return ErrUnsupportedPtrType{rf, t, structField}
57+
}
58+
4859
// UnmarshalPayload converts an io into a struct instance using jsonapi tags on
4960
// struct fields. This method supports single request payloads only, at the
5061
// moment. Bulk creates and updates are not supported yet.
@@ -129,7 +140,6 @@ func UnmarshalManyPayload(in io.Reader, t reflect.Type) ([]interface{}, error) {
129140
}
130141

131142
func unmarshalNode(data *Node, model reflect.Value, included *map[string]*Node) (err error) {
132-
133143
defer func() {
134144
if r := recover(); r != nil {
135145
err = fmt.Errorf("data is not a jsonapi representation of '%v'", model.Type())
@@ -375,8 +385,11 @@ func assign(field, value reflect.Value) {
375385
}
376386
}
377387

378-
func unmarshalAttribute(attribute interface{}, args []string, structField reflect.StructField, fieldValue reflect.Value) (value reflect.Value, err error) {
379-
388+
func unmarshalAttribute(
389+
attribute interface{},
390+
args []string,
391+
structField reflect.StructField,
392+
fieldValue reflect.Value) (value reflect.Value, err error) {
380393
value = reflect.ValueOf(attribute)
381394
fieldType := structField.Type
382395

@@ -387,7 +400,8 @@ func unmarshalAttribute(attribute interface{}, args []string, structField reflec
387400
}
388401

389402
// Handle field of type time.Time
390-
if fieldValue.Type() == reflect.TypeOf(time.Time{}) || fieldValue.Type() == reflect.TypeOf(new(time.Time)) {
403+
if fieldValue.Type() == reflect.TypeOf(time.Time{}) ||
404+
fieldValue.Type() == reflect.TypeOf(new(time.Time)) {
391405
value, err = handleTime(attribute, args, fieldType, fieldValue)
392406
return
393407
}
@@ -399,7 +413,8 @@ func unmarshalAttribute(attribute interface{}, args []string, structField reflec
399413
}
400414

401415
// Handle field containing slice of structs
402-
if fieldValue.Type().Kind() == reflect.Slice && reflect.TypeOf(fieldValue.Interface()).Elem().Kind() == reflect.Struct {
416+
if fieldValue.Type().Kind() == reflect.Slice &&
417+
reflect.TypeOf(fieldValue.Interface()).Elem().Kind() == reflect.Struct {
403418
value, err = handleStructSlice(attribute, args, fieldType, fieldValue)
404419
return
405420
}
@@ -425,7 +440,11 @@ func unmarshalAttribute(attribute interface{}, args []string, structField reflec
425440
return
426441
}
427442

428-
func handleStringSlice(attribute interface{}, args []string, fieldType reflect.Type, fieldValue reflect.Value) (reflect.Value, error) {
443+
func handleStringSlice(
444+
attribute interface{},
445+
args []string,
446+
fieldType reflect.Type,
447+
fieldValue reflect.Value) (reflect.Value, error) {
429448
v := reflect.ValueOf(attribute)
430449
values := make([]string, v.Len())
431450
for i := 0; i < v.Len(); i++ {
@@ -435,8 +454,11 @@ func handleStringSlice(attribute interface{}, args []string, fieldType reflect.T
435454
return reflect.ValueOf(values), nil
436455
}
437456

438-
func handleTime(attribute interface{}, args []string, fieldType reflect.Type, fieldValue reflect.Value) (reflect.Value, error) {
439-
457+
func handleTime(
458+
attribute interface{},
459+
args []string,
460+
fieldType reflect.Type,
461+
fieldValue reflect.Value) (reflect.Value, error) {
440462
var isIso8601 bool
441463
v := reflect.ValueOf(attribute)
442464

@@ -483,7 +505,11 @@ func handleTime(attribute interface{}, args []string, fieldType reflect.Type, fi
483505
return reflect.ValueOf(t), nil
484506
}
485507

486-
func handleNumeric(attribute interface{}, args []string, fieldType reflect.Type, fieldValue reflect.Value) (reflect.Value, error) {
508+
func handleNumeric(
509+
attribute interface{},
510+
args []string,
511+
fieldType reflect.Type,
512+
fieldValue reflect.Value) (reflect.Value, error) {
487513
v := reflect.ValueOf(attribute)
488514
floatValue := v.Interface().(float64)
489515

@@ -540,7 +566,12 @@ func handleNumeric(attribute interface{}, args []string, fieldType reflect.Type,
540566
return numericValue, nil
541567
}
542568

543-
func handlePointer(attribute interface{}, args []string, fieldType reflect.Type, fieldValue reflect.Value, structField reflect.StructField) (reflect.Value, error) {
569+
func handlePointer(
570+
attribute interface{},
571+
args []string,
572+
fieldType reflect.Type,
573+
fieldValue reflect.Value,
574+
structField reflect.StructField) (reflect.Value, error) {
544575
t := fieldValue.Type()
545576
var concreteVal reflect.Value
546577

@@ -549,50 +580,55 @@ func handlePointer(attribute interface{}, args []string, fieldType reflect.Type,
549580
concreteVal = reflect.ValueOf(&cVal)
550581
case bool:
551582
concreteVal = reflect.ValueOf(&cVal)
552-
case complex64:
553-
concreteVal = reflect.ValueOf(&cVal)
554-
case complex128:
555-
concreteVal = reflect.ValueOf(&cVal)
556-
case uintptr:
583+
case complex64, complex128, uintptr:
557584
concreteVal = reflect.ValueOf(&cVal)
558585
case map[string]interface{}:
559586
var err error
560587
concreteVal, err = handleStruct(attribute, args, fieldType, fieldValue)
561588
if err != nil {
562-
return reflect.Value{}, ErrUnsupportedPtrType(reflect.ValueOf(attribute), fieldType, structField)
589+
return reflect.Value{}, newErrUnsupportedPtrType(
590+
reflect.ValueOf(attribute), fieldType, structField)
563591
}
564592
return concreteVal.Elem(), err
565593
default:
566-
return reflect.Value{}, ErrUnsupportedPtrType(reflect.ValueOf(attribute), fieldType, structField)
594+
return reflect.Value{}, newErrUnsupportedPtrType(
595+
reflect.ValueOf(attribute), fieldType, structField)
567596
}
568597

569598
if t != concreteVal.Type() {
570-
return reflect.Value{}, ErrUnsupportedPtrType(reflect.ValueOf(attribute), fieldType, structField)
599+
return reflect.Value{}, newErrUnsupportedPtrType(
600+
reflect.ValueOf(attribute), fieldType, structField)
571601
}
572602

573603
return concreteVal, nil
574604
}
575605

576-
func handleStruct(attribute interface{}, args []string, fieldType reflect.Type, fieldValue reflect.Value) (reflect.Value, error) {
606+
func handleStruct(
607+
attribute interface{},
608+
args []string,
609+
fieldType reflect.Type,
610+
fieldValue reflect.Value) (reflect.Value, error) {
577611
model := reflect.New(fieldValue.Type())
578612

579-
var er error
580-
581-
data, er := json.Marshal(attribute)
582-
if er != nil {
583-
return model, er
613+
data, err := json.Marshal(attribute)
614+
if err != nil {
615+
return model, err
584616
}
585617

586-
er = json.Unmarshal(data, model.Interface())
618+
err = json.Unmarshal(data, model.Interface())
587619

588-
if er != nil {
589-
return model, er
620+
if err != nil {
621+
return model, err
590622
}
591623

592-
return model, er
624+
return model, err
593625
}
594626

595-
func handleStructSlice(attribute interface{}, args []string, fieldType reflect.Type, fieldValue reflect.Value) (reflect.Value, error) {
627+
func handleStructSlice(
628+
attribute interface{},
629+
args []string,
630+
fieldType reflect.Type,
631+
fieldValue reflect.Value) (reflect.Value, error) {
596632
models := reflect.New(fieldValue.Type()).Elem()
597633
dataMap := reflect.ValueOf(attribute).Interface().([]interface{})
598634
for _, data := range dataMap {

request_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ func TestUnmarshalToStructWithPointerAttr_BadType_bool(t *testing.T) {
136136
if err.Error() != expectedErrorMessage {
137137
t.Fatalf("Unexpected error message: %s", err.Error())
138138
}
139+
if _, ok := err.(ErrUnsupportedPtrType); !ok {
140+
t.Fatalf("Unexpected error type: %s", reflect.TypeOf(err))
141+
}
139142
}
140143

141144
func TestUnmarshalToStructWithPointerAttr_BadType_MapPtr(t *testing.T) {
@@ -153,6 +156,9 @@ func TestUnmarshalToStructWithPointerAttr_BadType_MapPtr(t *testing.T) {
153156
if err.Error() != expectedErrorMessage {
154157
t.Fatalf("Unexpected error message: %s", err.Error())
155158
}
159+
if _, ok := err.(ErrUnsupportedPtrType); !ok {
160+
t.Fatalf("Unexpected error type: %s", reflect.TypeOf(err))
161+
}
156162
}
157163

158164
func TestUnmarshalToStructWithPointerAttr_BadType_Struct(t *testing.T) {
@@ -171,6 +177,9 @@ func TestUnmarshalToStructWithPointerAttr_BadType_Struct(t *testing.T) {
171177
if err.Error() != expectedErrorMessage {
172178
t.Fatalf("Unexpected error message: %s", err.Error())
173179
}
180+
if _, ok := err.(ErrUnsupportedPtrType); !ok {
181+
t.Fatalf("Unexpected error type: %s", reflect.TypeOf(err))
182+
}
174183
}
175184

176185
func TestUnmarshalToStructWithPointerAttr_BadType_IntSlice(t *testing.T) {
@@ -189,6 +198,9 @@ func TestUnmarshalToStructWithPointerAttr_BadType_IntSlice(t *testing.T) {
189198
if err.Error() != expectedErrorMessage {
190199
t.Fatalf("Unexpected error message: %s", err.Error())
191200
}
201+
if _, ok := err.(ErrUnsupportedPtrType); !ok {
202+
t.Fatalf("Unexpected error type: %s", reflect.TypeOf(err))
203+
}
192204
}
193205

194206
func TestStringPointerField(t *testing.T) {

0 commit comments

Comments
 (0)