@@ -17,6 +17,7 @@ type DefaultBinder struct {
1717 ArrayMatcher * regexp.Regexp
1818 MapMatcher * regexp.Regexp
1919 ArrayNotationMatcher * regexp.Regexp
20+ DeepObjectSeparator string
2021 MaxBodySize int64
2122 MaxArraySize int
2223 HeaderTagName string
@@ -40,6 +41,7 @@ func NewBinder() *DefaultBinder {
4041 FormTagName : DefaultFormTagName ,
4142 QueryTagName : DefaultQueryTagName ,
4243 ParamTagName : DefaultParamTagName ,
44+ DeepObjectSeparator : DefaultDeepObjectSeparator ,
4345 BindOrder : []BindFunc {},
4446 }
4547
@@ -205,14 +207,20 @@ func (b *DefaultBinder) bindData(destination interface{}, data map[string][]stri
205207 }
206208
207209 // !struct
208- if typ .Kind () != reflect .Struct {
210+ if typ .Kind () != reflect .Struct && typ . Kind () != reflect . Ptr {
209211 if tag == b .ParamTagName || tag == b .QueryTagName || tag == b .HeaderTagName {
210212 // incompatible type, data is probably to be found in the body
211213 return nil
212214 }
213215 return errors .New ("binding element must be a struct" )
214216 }
215217
218+ // deference struct
219+ if typ .Kind () == reflect .Ptr {
220+ typ = typ .Elem ()
221+ val = val .Elem ()
222+ }
223+
216224 for i := 0 ; i < typ .NumField (); i ++ { // iterate over all destination fields
217225 typeField := typ .Field (i )
218226 structField := val .Field (i )
@@ -226,7 +234,6 @@ func (b *DefaultBinder) bindData(destination interface{}, data map[string][]stri
226234 }
227235 structFieldKind := structField .Kind ()
228236 inputFieldName := typeField .Tag .Get (tag )
229- // valueKind := structField.Type().Kind()
230237
231238 if typeField .Anonymous && structFieldKind == reflect .Struct && inputFieldName != "" {
232239 // if anonymous struct with query/param/form tags, report an error
@@ -258,25 +265,25 @@ func (b *DefaultBinder) bindData(destination interface{}, data map[string][]stri
258265 //if the field is a struct, we need to recursively bind data to it
259266 if structFieldKind == reflect .Struct {
260267 // the data now is only the data that is relevant to the current struct
261- structData := trimData (inputFieldName , data , b .ArrayNotationMatcher )
262- structFiles := trimFileFields (inputFieldName , dataFiles , b .ArrayNotationMatcher )
268+ structData := trimData (inputFieldName , data , b .ArrayNotationMatcher , b . DeepObjectSeparator )
269+ structFiles := trimFileFields (inputFieldName , dataFiles , b .ArrayNotationMatcher , b . DeepObjectSeparator )
263270 if err := b .bindData (structField .Addr ().Interface (), structData , tag , structFiles ); err != nil {
264271 return err
265272 }
266273 continue
267274 } else if structFieldKind == reflect .Map {
268275 // the data now is only the data that is relevant to the current field
269- mapData := trimData (inputFieldName , data , b .MapMatcher )
270- mapFiles := trimFileFields (inputFieldName , dataFiles , b .MapMatcher )
276+ mapData := trimData (inputFieldName , data , b .MapMatcher , b . DeepObjectSeparator )
277+ mapFiles := trimFileFields (inputFieldName , dataFiles , b .MapMatcher , b . DeepObjectSeparator )
271278 if err := b .bindData (structField .Addr ().Interface (), mapData , tag , mapFiles ); err != nil {
272279 return err
273280 }
274281 // continue
275282 } else if structFieldKind == reflect .Slice {
276283 // the data now is only the data that is relevant to the current field
277284
278- sliceData := trimData (inputFieldName , data , b .ArrayMatcher )
279- sliceFiles := trimFileFields (inputFieldName , dataFiles , b .ArrayMatcher )
285+ sliceData := trimData (inputFieldName , data , b .ArrayMatcher , b . DeepObjectSeparator )
286+ sliceFiles := trimFileFields (inputFieldName , dataFiles , b .ArrayMatcher , b . DeepObjectSeparator )
280287 if err := handleArrayValues (structField , structFieldKind , sliceData , sliceFiles , inputFieldName , b .MaxArraySize ); err != nil {
281288 return err
282289 }
@@ -299,6 +306,61 @@ func (b *DefaultBinder) bindData(destination interface{}, data map[string][]stri
299306 }
300307
301308 if ! exists {
309+
310+ if structFieldKind == reflect .Ptr { // if the field is a pointer, we need to check if it is a struct
311+
312+ elem := typeField .Type .Elem () // get the type of the pointer
313+ valueKind := elem .Kind ()
314+ if valueKind == reflect .Struct {
315+ structData := trimData (inputFieldName , data , b .ArrayNotationMatcher , b .DeepObjectSeparator )
316+ structFiles := trimFileFields (inputFieldName , dataFiles , b .ArrayNotationMatcher , b .DeepObjectSeparator )
317+
318+ if len (structData ) == 0 && len (structFiles ) == 0 { // no data for this field
319+ continue
320+ }
321+
322+ if structField .IsNil () {
323+ structField .Set (reflect .New (structField .Type ().Elem ()))
324+ }
325+
326+ // fmt.Println("structFiles", structFiles)
327+ if err := b .bindData (structField .Addr ().Interface (), structData , tag , structFiles ); err != nil {
328+ return err
329+ }
330+ continue
331+ } else if valueKind == reflect .Slice {
332+ // the data now is only the data that is relevant to the current field
333+ sliceData := trimData (inputFieldName , data , b .ArrayMatcher , b .DeepObjectSeparator )
334+ sliceFiles := trimFileFields (inputFieldName , dataFiles , b .ArrayMatcher , b .DeepObjectSeparator )
335+
336+ if len (sliceData ) == 0 && len (sliceFiles ) == 0 { // no data for this field
337+ continue
338+ }
339+
340+ if structField .IsNil () {
341+ structField .Set (reflect .New (structField .Type ().Elem ()))
342+ }
343+
344+ if err := handleArrayValues (structField , structFieldKind , sliceData , sliceFiles , inputFieldName , b .MaxArraySize ); err != nil {
345+ return err
346+ }
347+ } else if valueKind == reflect .Map {
348+ // the data now is only the data that is relevant to the current field
349+ mapData := trimData (inputFieldName , data , b .MapMatcher , b .DeepObjectSeparator )
350+ mapFiles := trimFileFields (inputFieldName , dataFiles , b .MapMatcher , b .DeepObjectSeparator )
351+
352+ if len (mapData ) == 0 && len (mapFiles ) == 0 { // no data for this field
353+ continue
354+ }
355+ if structField .IsNil () {
356+ structField .Set (reflect .New (structField .Type ().Elem ()))
357+ }
358+
359+ if err := b .bindData (structField .Interface (), mapData , tag , mapFiles ); err != nil {
360+ return err
361+ }
362+ }
363+ }
302364 continue
303365 }
304366
0 commit comments