Skip to content

Commit fa25271

Browse files
committed
feat(binding): add support for encoding.UnmarshalText in uri/query binding
1 parent 61c2b1c commit fa25271

File tree

3 files changed

+526
-117
lines changed

3 files changed

+526
-117
lines changed

binding/form_mapping.go

Lines changed: 49 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package binding
66

77
import (
8+
"encoding"
89
"errors"
910
"fmt"
1011
"mime/multipart"
@@ -136,6 +137,7 @@ func mapping(value reflect.Value, field reflect.StructField, setter setter, tag
136137
type setOptions struct {
137138
isDefaultExists bool
138139
defaultValue string
140+
parser string
139141
}
140142

141143
func tryToSetValue(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) {
@@ -167,6 +169,8 @@ func tryToSetValue(value reflect.Value, field reflect.StructField, setter setter
167169
setOpt.defaultValue = strings.ReplaceAll(v, ";", ",")
168170
}
169171
}
172+
} else if k, v = head(opt, "="); k == "parser" {
173+
setOpt.parser = v
170174
}
171175
}
172176

@@ -190,6 +194,20 @@ func trySetCustom(val string, value reflect.Value) (isSet bool, err error) {
190194
return false, nil
191195
}
192196

197+
// trySetUsingParser tries to set a custom type value based on the presence of the "parser" tag on the field.
198+
// If the parser tag does not exist or does not match any of the supported parsers, gin will skip over this.
199+
func trySetUsingParser(val string, value reflect.Value, parser string) (isSet bool, err error) {
200+
switch parser {
201+
case "encoding.TextUnmarshaler":
202+
v, ok := value.Addr().Interface().(encoding.TextUnmarshaler)
203+
if !ok {
204+
return false, nil
205+
}
206+
return true, v.UnmarshalText([]byte(val))
207+
}
208+
return false, nil
209+
}
210+
193211
func trySplit(vs []string, field reflect.StructField) (newVs []string, err error) {
194212
cfTag := field.Tag.Get("collection_format")
195213
if cfTag == "" || cfTag == "multi" {
@@ -207,7 +225,7 @@ func trySplit(vs []string, field reflect.StructField) (newVs []string, err error
207225
case "pipes":
208226
sep = "|"
209227
default:
210-
return vs, fmt.Errorf("%s is not supported in the collection_format. (csv, ssv, pipes)", cfTag)
228+
return vs, fmt.Errorf("%s is not supported in the collection_format. (multi, csv, ssv, tsv, pipes)", cfTag)
211229
}
212230

213231
totalLength := 0
@@ -230,7 +248,7 @@ func setByForm(value reflect.Value, field reflect.StructField, form map[string][
230248

231249
switch value.Kind() {
232250
case reflect.Slice:
233-
if !ok {
251+
if !ok || len(vs) == 0 || (len(vs) > 0 && vs[0] == "") {
234252
vs = []string{opt.defaultValue}
235253

236254
// pre-process the default value for multi if present
@@ -240,17 +258,19 @@ func setByForm(value reflect.Value, field reflect.StructField, form map[string][
240258
}
241259
}
242260

243-
if ok, err = trySetCustom(vs[0], value); ok {
261+
if ok, err = trySetUsingParser(vs[0], value, opt.parser); ok {
262+
return ok, err
263+
} else if ok, err = trySetCustom(vs[0], value); ok {
244264
return ok, err
245265
}
246266

247267
if vs, err = trySplit(vs, field); err != nil {
248268
return false, err
249269
}
250270

251-
return true, setSlice(vs, value, field)
271+
return true, setSlice(vs, value, field, opt)
252272
case reflect.Array:
253-
if !ok {
273+
if !ok || len(vs) == 0 || (len(vs) > 0 && vs[0] == "") {
254274
vs = []string{opt.defaultValue}
255275

256276
// pre-process the default value for multi if present
@@ -260,7 +280,9 @@ func setByForm(value reflect.Value, field reflect.StructField, form map[string][
260280
}
261281
}
262282

263-
if ok, err = trySetCustom(vs[0], value); ok {
283+
if ok, err = trySetUsingParser(vs[0], value, opt.parser); ok {
284+
return ok, err
285+
} else if ok, err = trySetCustom(vs[0], value); ok {
264286
return ok, err
265287
}
266288

@@ -272,27 +294,32 @@ func setByForm(value reflect.Value, field reflect.StructField, form map[string][
272294
return false, fmt.Errorf("%q is not valid value for %s", vs, value.Type().String())
273295
}
274296

275-
return true, setArray(vs, value, field)
297+
return true, setArray(vs, value, field, opt)
276298
default:
277299
var val string
278-
if !ok {
300+
if !ok || len(vs) == 0 || (len(vs) > 0 && vs[0] == "") {
279301
val = opt.defaultValue
280-
}
281-
282-
if len(vs) > 0 {
302+
} else if len(vs) > 0 {
283303
val = vs[0]
284-
if val == "" {
285-
val = opt.defaultValue
286-
}
287304
}
288-
if ok, err := trySetCustom(val, value); ok {
305+
306+
if ok, err = trySetUsingParser(val, value, opt.parser); ok {
307+
return ok, err
308+
} else if ok, err = trySetCustom(val, value); ok {
289309
return ok, err
290310
}
291-
return true, setWithProperType(val, value, field)
311+
return true, setWithProperType(val, value, field, opt)
292312
}
293313
}
294314

295-
func setWithProperType(val string, value reflect.Value, field reflect.StructField) error {
315+
func setWithProperType(val string, value reflect.Value, field reflect.StructField, opt setOptions) error {
316+
// this if-check is required for parsing nested types like []MyId, where MyId is [12]byte
317+
if ok, err := trySetUsingParser(val, value, opt.parser); ok {
318+
return err
319+
} else if ok, err = trySetCustom(val, value); ok {
320+
return err
321+
}
322+
296323
switch value.Kind() {
297324
case reflect.Int:
298325
return setIntField(val, 0, value)
@@ -340,7 +367,7 @@ func setWithProperType(val string, value reflect.Value, field reflect.StructFiel
340367
if !value.Elem().IsValid() {
341368
value.Set(reflect.New(value.Type().Elem()))
342369
}
343-
return setWithProperType(val, value.Elem(), field)
370+
return setWithProperType(val, value.Elem(), field, opt)
344371
default:
345372
return errUnknownType
346373
}
@@ -447,19 +474,19 @@ func setTimeField(val string, structField reflect.StructField, value reflect.Val
447474
return nil
448475
}
449476

450-
func setArray(vals []string, value reflect.Value, field reflect.StructField) error {
477+
func setArray(vals []string, value reflect.Value, field reflect.StructField, opt setOptions) error {
451478
for i, s := range vals {
452-
err := setWithProperType(s, value.Index(i), field)
479+
err := setWithProperType(s, value.Index(i), field, opt)
453480
if err != nil {
454481
return err
455482
}
456483
}
457484
return nil
458485
}
459486

460-
func setSlice(vals []string, value reflect.Value, field reflect.StructField) error {
487+
func setSlice(vals []string, value reflect.Value, field reflect.StructField, opt setOptions) error {
461488
slice := reflect.MakeSlice(value.Type(), len(vals), len(vals))
462-
err := setArray(vals, slice, field)
489+
err := setArray(vals, slice, field, opt)
463490
if err != nil {
464491
return err
465492
}

0 commit comments

Comments
 (0)