11package jrpc2
22
33import (
4+ "encoding"
45 "encoding/hex"
56 "encoding/json"
67 "errors"
@@ -312,6 +313,10 @@ func GetNamedParams(target Method) map[string]interface{} {
312313}
313314
314315func isZero (x interface {}) bool {
316+ if x == nil {
317+ return true
318+ }
319+
315320 return reflect .DeepEqual (x , reflect .Zero (reflect .TypeOf (x )).Interface ())
316321}
317322
@@ -354,10 +359,7 @@ func ParseNamedParams(target Method, params map[string]interface{}) error {
354359 targetValue := reflect .Indirect (reflect .ValueOf (target ))
355360 err := innerParseNamed (targetValue , params )
356361 if err != nil {
357- fmt .Println ("ERR" )
358- fmt .Println (err )
359- fmt .Println (targetValue )
360- fmt .Println (params )
362+ return err
361363 }
362364 return nil
363365}
@@ -372,11 +374,16 @@ func innerParseNamed(targetValue reflect.Value, params map[string]interface{}) e
372374 continue
373375 }
374376 fT := tType .Field (i )
375- // check for the json tag match, as well a simple
376- // lower case name match
377377 tag , _ := fT .Tag .Lookup ("json" )
378- if tag == key || key == strings .ToLower (fT .Name ) {
378+
379+ name , omit := parseTag (tag )
380+
381+ if name == key || key == strings .ToLower (fT .Name ) {
379382 found = true
383+ if omit && isZero (value ) {
384+ break
385+ }
386+
380387 err := innerParse (targetValue , fVal , value )
381388 if err != nil {
382389 return err
@@ -411,14 +418,12 @@ func innerParse(targetValue reflect.Value, fVal reflect.Value, value interface{}
411418 }
412419
413420 // json.RawMessage escape hatch
414- var eg json.RawMessage
415- if fVal .Type () == reflect .TypeOf (eg ) {
421+ if strings .Contains (fVal .Type ().String (), "RawMessage" ) {
416422 out , err := json .Marshal (value )
417423 if err != nil {
418424 return err
419425 }
420- jm := json .RawMessage (out )
421- fVal .Set (reflect .ValueOf (jm ))
426+ fVal .Set (reflect .ValueOf (out ).Convert (fVal .Type ()))
422427 return nil
423428 }
424429
@@ -473,8 +478,12 @@ func innerParse(targetValue reflect.Value, fVal reflect.Value, value interface{}
473478 return nil
474479 }
475480
476- av := value .([]interface {})
481+ av , ok := value .([]interface {})
482+ if ! ok {
483+ return NewError (nil , InvalidParams , fmt .Sprintf ("Expected JSON array for slice field %s, but got %T" , fVal .Type ().Name (), value ))
484+ }
477485 fVal .Set (reflect .MakeSlice (fVal .Type (), len (av ), len (av )))
486+
478487 for i := range av {
479488 err := innerParse (targetValue , fVal .Index (i ), av [i ])
480489 if err != nil {
@@ -517,22 +526,71 @@ func innerParse(targetValue reflect.Value, fVal reflect.Value, value interface{}
517526 }
518527 case reflect .Ptr :
519528 if v .Kind () == reflect .Invalid {
520- // i'm afraid that's a nil, my dear
521529 return nil
522530 }
531+
532+ umType := reflect .TypeOf ((* json .Unmarshaler )(nil )).Elem ()
533+ tmType := reflect .TypeOf ((* encoding .TextUnmarshaler )(nil )).Elem ()
534+ ptrType := fVal .Type ()
535+
536+ // if the pointer itself implements Unmarshaler,
537+ // or if the thing it points to does,
538+ // then we can use that to unmarshal this value
539+ if ptrType .Implements (umType ) || reflect .PointerTo (ptrType .Elem ()).Implements (umType ) {
540+ n := reflect .New (ptrType .Elem ())
541+ data , err := json .Marshal (value )
542+ if err != nil {
543+ return err
544+ }
545+ if err := json .Unmarshal (data , n .Interface ()); err != nil {
546+ return err
547+ }
548+ fVal .Set (n )
549+ return nil
550+ }
551+
552+ // Handle types implementing encoding.TextUnmarshaler by parsing from a string and setting the field.
553+ if ptrType .Implements (tmType ) || reflect .PointerTo (ptrType .Elem ()).Implements (tmType ) {
554+ s , ok := value .(string )
555+ if ! ok {
556+ return NewError (nil , InvalidParams , fmt .Sprintf ("Expected string input for %s.%s, but got %T" , targetValue .Type ().Name (), fVal .Type ().Name (), value ))
557+ }
558+ n := reflect .New (ptrType .Elem ())
559+ if err := n .Interface ().(encoding.TextUnmarshaler ).UnmarshalText ([]byte (s )); err != nil {
560+ return err
561+ }
562+ fVal .Set (n )
563+ return nil
564+ }
565+
566+ // For pointer-to-non-struct fields, allocate a new element,
567+ // parse into it, then assign the pointer.
568+ if fVal .Type ().Elem ().Kind () != reflect .Struct {
569+ n := reflect .New (fVal .Type ().Elem ())
570+ err := innerParse (targetValue , n .Elem (), value )
571+ if err != nil {
572+ return err
573+ }
574+ fVal .Set (n )
575+ return nil
576+ }
577+
523578 if v .Kind () != reflect .Map {
524579 return NewError (nil , InvalidParams , fmt .Sprintf ("Types don't match. Expected a map[string]interface{} from the JSON, instead got %s" , v .Kind ().String ()))
525580 }
581+
526582 if fVal .IsNil () {
527583 // You need a new pointer object thing here
528584 // so allocate one with this voodoo-magique
529585 fVal .Set (reflect .New (fVal .Type ().Elem ()))
530586 }
587+
531588 return innerParseNamed (fVal .Elem (), value .(map [string ]interface {}))
532589 case reflect .Struct :
533590 if v .Kind () != reflect .Map {
534591 return NewError (nil , InvalidParams , fmt .Sprintf ("Types don't match. Expected a map[string]interface{} from the JSON, instead got %s" , v .Kind ().String ()))
535592 }
593+
536594 return innerParseNamed (fVal , value .(map [string ]interface {}))
537595 case reflect .String :
538596 fVal .SetString (fmt .Sprintf ("%v" , v ))
0 commit comments