@@ -353,7 +353,6 @@ func (v *Validate) structRecursive(top interface{}, current interface{}, s inter
353353 structName = structType .Name ()
354354 numFields = structValue .NumField ()
355355 cs = & cachedStruct {name : structName , children : numFields }
356- structCache .Set (structType , cs )
357356 }
358357
359358 validationErrors := structPool .Borrow ()
@@ -429,24 +428,62 @@ func (v *Validate) structRecursive(top interface{}, current interface{}, s inter
429428 continue
430429 }
431430
432- if valueField .Kind () == reflect .Ptr && valueField .IsNil () {
431+ if ( valueField .Kind () == reflect .Ptr || cField . kind == reflect . Interface ) && valueField .IsNil () {
433432
434433 if strings .Contains (cField .tag , omitempty ) {
435- continue
434+ goto CACHEFIELD
436435 }
437436
438- if strings .Contains (cField .tag , required ) {
437+ tags := strings .Split (cField .tag , tagSeparator )
438+
439+ if len (tags ) > 0 {
440+
441+ var param string
442+ vals := strings .SplitN (tags [0 ], tagKeySeparator , 2 )
443+
444+ if len (vals ) > 1 {
445+ param = vals [1 ]
446+ }
439447
440448 validationErrors .Errors [cField .name ] = & FieldError {
441449 Field : cField .name ,
442- Tag : required ,
450+ Tag : vals [0 ],
451+ Param : param ,
443452 Value : valueField .Interface (),
453+ Kind : valueField .Kind (),
454+ Type : valueField .Type (),
444455 }
445456
446- continue
457+ goto CACHEFIELD
458+ }
459+ }
460+
461+ // if we get here, the field is interface and could be a struct or a field
462+ // and we need to check the inner type and validate
463+ if cField .kind == reflect .Interface {
464+
465+ valueField = valueField .Elem ()
466+
467+ if valueField .Kind () == reflect .Ptr && ! valueField .IsNil () {
468+ valueField = valueField .Elem ()
469+ }
470+
471+ if valueField .Kind () == reflect .Struct {
472+ goto VALIDATESTRUCT
473+ }
474+
475+ // sending nil for cField as it was type interface and could be anything
476+ // each time and so must be calculated each time and can't be cached reliably
477+ if fieldError := v .fieldWithNameAndValue (top , current , valueField .Interface (), cField .tag , cField .name , false , nil ); fieldError != nil {
478+ validationErrors .Errors [fieldError .Field ] = fieldError
479+ // free up memory reference
480+ fieldError = nil
447481 }
482+
483+ goto CACHEFIELD
448484 }
449485
486+ VALIDATESTRUCT:
450487 if structErrors := v .structRecursive (top , valueField .Interface (), valueField .Interface ()); structErrors != nil {
451488 validationErrors .StructErrors [cField .name ] = structErrors
452489 // free up memory map no longer needed
@@ -486,11 +523,14 @@ func (v *Validate) structRecursive(top interface{}, current interface{}, s inter
486523 }
487524 }
488525
526+ CACHEFIELD:
489527 if ! isCached {
490528 cs .fields = append (cs .fields , cField )
491529 }
492530 }
493531
532+ structCache .Set (structType , cs )
533+
494534 if len (validationErrors .Errors ) == 0 && len (validationErrors .StructErrors ) == 0 {
495535 structPool .Return (validationErrors )
496536 return nil
@@ -709,26 +749,60 @@ func (v *Validate) traverseMap(val interface{}, current interface{}, valueField
709749 continue
710750 }
711751
712- if idxField .Kind () == reflect .Ptr && idxField .IsNil () {
752+ if ( idxField .Kind () == reflect .Ptr || idxField . Kind () == reflect . Interface ) && idxField .IsNil () {
713753
714- if strings .Contains (cField .tag , omitempty ) {
754+ if strings .Contains (cField .diveTag , omitempty ) {
715755 continue
716756 }
717757
718- if strings .Contains (cField .tag , required ) {
758+ tags := strings .Split (cField .diveTag , tagSeparator )
759+
760+ if len (tags ) > 0 {
761+
762+ var param string
763+ vals := strings .SplitN (tags [0 ], tagKeySeparator , 2 )
764+
765+ if len (vals ) > 1 {
766+ param = vals [1 ]
767+ }
719768
720769 errs [key .Interface ()] = & FieldError {
721770 Field : fmt .Sprintf (mapIndexFieldName , cField .name , key .Interface ()),
722- Tag : required ,
771+ Tag : vals [0 ],
772+ Param : param ,
723773 Value : idxField .Interface (),
724- Kind : reflect . Ptr ,
774+ Kind : idxField . Kind () ,
725775 Type : cField .mapSubtype ,
726776 }
727777 }
728778
729779 continue
730780 }
731781
782+ // if we get here, the field is interface and could be a struct or a field
783+ // and we need to check the inner type and validate
784+ if idxField .Kind () == reflect .Interface {
785+
786+ idxField = idxField .Elem ()
787+
788+ if idxField .Kind () == reflect .Ptr && ! idxField .IsNil () {
789+ idxField = idxField .Elem ()
790+ }
791+
792+ if idxField .Kind () == reflect .Struct {
793+ goto VALIDATESTRUCT
794+ }
795+
796+ // sending nil for cField as it was type interface and could be anything
797+ // each time and so must be calculated each time and can't be cached reliably
798+ if fieldError := v .fieldWithNameAndValue (val , current , idxField .Interface (), cField .diveTag , fmt .Sprintf (mapIndexFieldName , cField .name , key .Interface ()), false , nil ); fieldError != nil {
799+ errs [key .Interface ()] = fieldError
800+ }
801+
802+ continue
803+ }
804+
805+ VALIDATESTRUCT:
732806 if structErrors := v .structRecursive (val , current , idxField .Interface ()); structErrors != nil {
733807 errs [key .Interface ()] = structErrors
734808 }
@@ -768,26 +842,60 @@ func (v *Validate) traverseSliceOrArray(val interface{}, current interface{}, va
768842 continue
769843 }
770844
771- if idxField .Kind () == reflect .Ptr && idxField .IsNil () {
845+ if ( idxField .Kind () == reflect .Ptr || idxField . Kind () == reflect . Interface ) && idxField .IsNil () {
772846
773- if strings .Contains (cField .tag , omitempty ) {
847+ if strings .Contains (cField .diveTag , omitempty ) {
774848 continue
775849 }
776850
777- if strings .Contains (cField .tag , required ) {
851+ tags := strings .Split (cField .diveTag , tagSeparator )
852+
853+ if len (tags ) > 0 {
854+
855+ var param string
856+ vals := strings .SplitN (tags [0 ], tagKeySeparator , 2 )
857+
858+ if len (vals ) > 1 {
859+ param = vals [1 ]
860+ }
778861
779862 errs [i ] = & FieldError {
780863 Field : fmt .Sprintf (arrayIndexFieldName , cField .name , i ),
781- Tag : required ,
864+ Tag : vals [0 ],
865+ Param : param ,
782866 Value : idxField .Interface (),
783- Kind : reflect . Ptr ,
867+ Kind : idxField . Kind () ,
784868 Type : cField .sliceSubtype ,
785869 }
786870 }
787871
788872 continue
789873 }
790874
875+ // if we get here, the field is interface and could be a struct or a field
876+ // and we need to check the inner type and validate
877+ if idxField .Kind () == reflect .Interface {
878+
879+ idxField = idxField .Elem ()
880+
881+ if idxField .Kind () == reflect .Ptr && ! idxField .IsNil () {
882+ idxField = idxField .Elem ()
883+ }
884+
885+ if idxField .Kind () == reflect .Struct {
886+ goto VALIDATESTRUCT
887+ }
888+
889+ // sending nil for cField as it was type interface and could be anything
890+ // each time and so must be calculated each time and can't be cached reliably
891+ if fieldError := v .fieldWithNameAndValue (val , current , idxField .Interface (), cField .diveTag , fmt .Sprintf (arrayIndexFieldName , cField .name , i ), false , nil ); fieldError != nil {
892+ errs [i ] = fieldError
893+ }
894+
895+ continue
896+ }
897+
898+ VALIDATESTRUCT:
791899 if structErrors := v .structRecursive (val , current , idxField .Interface ()); structErrors != nil {
792900 errs [i ] = structErrors
793901 }
0 commit comments