1
1
/*
2
- * Copyright 2012- 2024 the original author or authors .
2
+ * Copyright 2024 The Go-Spring Authors .
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
@@ -24,7 +24,7 @@ import (
24
24
"strings"
25
25
26
26
"github.com/go-spring/spring-core/util"
27
- "github.com/go-spring/spring-core/util/macro "
27
+ "github.com/go-spring/spring-core/util/errutil "
28
28
)
29
29
30
30
var (
@@ -94,22 +94,27 @@ type BindParam struct {
94
94
}
95
95
96
96
func (param * BindParam ) BindTag (tag string , validate reflect.StructTag ) error {
97
+ param .Validate = validate
97
98
parsedTag , err := ParseTag (tag )
98
99
if err != nil {
99
100
return err
100
101
}
102
+ if parsedTag .Key == "" { // ${:=} 默认值语法
103
+ if parsedTag .HasDef {
104
+ param .Tag = parsedTag
105
+ return nil
106
+ }
107
+ return fmt .Errorf ("xxxx" ) // todo
108
+ }
101
109
if parsedTag .Key == "ROOT" {
102
110
parsedTag .Key = ""
103
- } else if parsedTag .Key == "" {
104
- parsedTag .Key = "ANONYMOUS"
105
111
}
106
- param .Tag = parsedTag
107
112
if param .Key == "" {
108
113
param .Key = parsedTag .Key
109
114
} else if parsedTag .Key != "" {
110
115
param .Key = param .Key + "." + parsedTag .Key
111
116
}
112
- param .Validate = validate
117
+ param .Tag = parsedTag
113
118
return nil
114
119
}
115
120
@@ -118,11 +123,11 @@ type Filter interface {
118
123
}
119
124
120
125
// BindValue binds properties to a value.
121
- func BindValue (p readOnlyProperties , v reflect.Value , t reflect.Type , param BindParam , filter Filter ) (RetErr error ) {
126
+ func BindValue (p ReadOnlyProperties , v reflect.Value , t reflect.Type , param BindParam , filter Filter ) (RetErr error ) {
122
127
123
- if ! util .IsValueType (t ) {
128
+ if ! util .IsPropBindingTarget (t ) {
124
129
err := errors .New ("target should be value type" )
125
- return fmt .Errorf ("%s: bind %s error, %w" , macro . FileLine (), param . Path , err )
130
+ return fmt .Errorf ("bind path=%s type= %s error: %w" , param . Path , v . Type (). String () , err )
126
131
}
127
132
128
133
defer func () {
@@ -144,29 +149,29 @@ func BindValue(p readOnlyProperties, v reflect.Value, t reflect.Type, param Bind
144
149
return bindSlice (p , v , t , param , filter )
145
150
case reflect .Array :
146
151
err := errors .New ("use slice instead of array" )
147
- return fmt .Errorf ("%s: bind %s error, %w" , macro . FileLine (), param . Path , err )
152
+ return fmt .Errorf ("bind path=%s type= %s error: %w" , param . Path , v . Type (). String () , err )
148
153
default : // for linter
149
154
}
150
155
151
156
fn := converters [t ]
152
157
if fn == nil && v .Kind () == reflect .Struct {
153
158
if err := bindStruct (p , v , t , param , filter ); err != nil {
154
- return fmt . Errorf ( "%s: bind %s error, %w" , macro . FileLine (), param . Path , err )
159
+ return err // no wrap
155
160
}
156
161
return nil
157
162
}
158
163
159
164
val , err := resolve (p , param )
160
165
if err != nil {
161
- return fmt . Errorf ( "%s: bind %s error, %w " , macro . FileLine (), param .Path , err )
166
+ return errutil . WrapError ( err , "bind path=%s type= %s error" , param .Path , v . Type (). String () )
162
167
}
163
168
164
169
if fn != nil {
165
170
fnValue := reflect .ValueOf (fn )
166
171
out := fnValue .Call ([]reflect.Value {reflect .ValueOf (val )})
167
172
if ! out [1 ].IsNil () {
168
173
err = out [1 ].Interface ().(error )
169
- return fmt . Errorf ( "%s: bind %s error, %w " , macro . FileLine (), param .Path , err )
174
+ return errutil . WrapError ( err , "bind path=%s type= %s error" , param .Path , v . Type (). String () )
170
175
}
171
176
v .Set (out [0 ])
172
177
return nil
@@ -179,45 +184,45 @@ func BindValue(p readOnlyProperties, v reflect.Value, t reflect.Type, param Bind
179
184
v .SetUint (u )
180
185
return nil
181
186
}
182
- return fmt . Errorf ( "%s: bind %s error, %w " , macro . FileLine (), param .Path , err )
187
+ return errutil . WrapError ( err , "bind path=%s type= %s error" , param .Path , v . Type (). String () )
183
188
case reflect .Int , reflect .Int8 , reflect .Int16 , reflect .Int32 , reflect .Int64 :
184
189
var i int64
185
190
if i , err = strconv .ParseInt (val , 0 , 0 ); err == nil {
186
191
v .SetInt (i )
187
192
return nil
188
193
}
189
- return fmt . Errorf ( "%s: bind %s error, %w " , macro . FileLine (), param .Path , err )
194
+ return errutil . WrapError ( err , "bind path=%s type= %s error" , param .Path , v . Type (). String () )
190
195
case reflect .Float32 , reflect .Float64 :
191
196
var f float64
192
197
if f , err = strconv .ParseFloat (val , 64 ); err == nil {
193
198
v .SetFloat (f )
194
199
return nil
195
200
}
196
- return fmt . Errorf ( "%s: bind %s error, %w " , macro . FileLine (), param .Path , err )
201
+ return errutil . WrapError ( err , "bind path=%s type= %s error" , param .Path , v . Type (). String () )
197
202
case reflect .Bool :
198
203
var b bool
199
204
if b , err = strconv .ParseBool (val ); err == nil {
200
205
v .SetBool (b )
201
206
return nil
202
207
}
203
- return fmt . Errorf ( "%s: bind %s error, %w " , macro . FileLine (), param .Path , err )
208
+ return errutil . WrapError ( err , "bind path=%s type= %s error" , param .Path , v . Type (). String () )
204
209
case reflect .String :
205
210
v .SetString (val )
206
211
return nil
207
212
default : // for linter
208
213
}
209
214
210
- err = fmt . Errorf ("unsupported bind type %q" , t . String () )
211
- return fmt .Errorf ("%s: bind %s error, %w" , macro . FileLine (), param . Path , err )
215
+ err = errors . New ("unsupported bind type" )
216
+ return fmt .Errorf ("bind path=%s type= %s error: %w" , param . Path , v . Type (). String () , err )
212
217
}
213
218
214
219
// bindSlice binds properties to a slice value.
215
- func bindSlice (p readOnlyProperties , v reflect.Value , t reflect.Type , param BindParam , filter Filter ) error {
220
+ func bindSlice (p ReadOnlyProperties , v reflect.Value , t reflect.Type , param BindParam , filter Filter ) error {
216
221
217
222
et := t .Elem ()
218
223
p , err := getSlice (p , et , param )
219
224
if err != nil {
220
- return fmt . Errorf ( "%s: bind %s error, %w " , macro . FileLine (), param .Path , err )
225
+ return errutil . WrapError ( err , "bind path=%s type= %s error" , param .Path , v . Type (). String () )
221
226
}
222
227
223
228
slice := reflect .MakeSlice (t , 0 , 0 )
@@ -238,14 +243,14 @@ func bindSlice(p readOnlyProperties, v reflect.Value, t reflect.Type, param Bind
238
243
break
239
244
}
240
245
if err != nil {
241
- return fmt . Errorf ( "%s: bind %s error, %w " , macro . FileLine (), param .Path , err )
246
+ return errutil . WrapError ( err , "bind path=%s type= %s error" , param .Path , v . Type (). String () )
242
247
}
243
248
slice = reflect .Append (slice , e )
244
249
}
245
250
return nil
246
251
}
247
252
248
- func getSlice (p readOnlyProperties , et reflect.Type , param BindParam ) (readOnlyProperties , error ) {
253
+ func getSlice (p ReadOnlyProperties , et reflect.Type , param BindParam ) (ReadOnlyProperties , error ) {
249
254
250
255
// properties that defined as list.
251
256
if p .Has (param .Key + "[0]" ) {
@@ -259,13 +264,13 @@ func getSlice(p readOnlyProperties, et reflect.Type, param BindParam) (readOnlyP
259
264
strVal = p .Get (param .Key )
260
265
} else {
261
266
if ! param .Tag .HasDef {
262
- return nil , fmt .Errorf ("%s: property %q %w" , macro . FileLine () , param .Key , ErrNotExist )
267
+ return nil , fmt .Errorf ("property %q %w" , param .Key , ErrNotExist )
263
268
}
264
269
if param .Tag .Def == "" {
265
270
return nil , nil
266
271
}
267
272
if ! util .IsPrimitiveValueType (et ) && converters [et ] == nil {
268
- return nil , fmt .Errorf ("%s: can't find converter for %s" , macro . FileLine () , et .String ())
273
+ return nil , fmt .Errorf ("can't find converter for %s" , et .String ())
269
274
}
270
275
strVal = param .Tag .Def
271
276
}
@@ -286,35 +291,44 @@ func getSlice(p readOnlyProperties, et reflect.Type, param BindParam) (readOnlyP
286
291
}
287
292
} else if fn , ok := splitters [s ]; ok && fn != nil {
288
293
if arrVal , err = fn (strVal ); err != nil {
289
- return nil , fmt .Errorf ("%s: split error: %w, value: %q" , macro . FileLine () , err , strVal )
294
+ return nil , fmt .Errorf ("split error: %w, value: %q" , err , strVal )
290
295
}
291
296
} else {
292
- return nil , fmt .Errorf ("%s: unknown splitter %q" , macro . FileLine () , s )
297
+ return nil , fmt .Errorf ("unknown splitter %q" , s )
293
298
}
294
299
295
300
r := New ()
296
301
for i , s := range arrVal {
297
302
k := fmt .Sprintf ("%s[%d]" , param .Key , i )
298
- _ = r .storage .Set (k , s )
303
+ if err = r .storage .Set (k , s ); err != nil {
304
+ return nil , err
305
+ }
299
306
}
300
307
return r , nil
301
308
}
302
309
303
310
// bindMap binds properties to a map value.
304
- func bindMap (p readOnlyProperties , v reflect.Value , t reflect.Type , param BindParam , filter Filter ) error {
311
+ func bindMap (p ReadOnlyProperties , v reflect.Value , t reflect.Type , param BindParam , filter Filter ) error {
305
312
306
313
if param .Tag .HasDef && param .Tag .Def != "" {
307
314
err := errors .New ("map can't have a non-empty default value" )
308
- return fmt .Errorf ("%s: bind %s error, %w" , macro . FileLine (), param . Path , err )
315
+ return fmt .Errorf ("bind path=%s type= %s error: %w" , param . Path , v . Type (). String () , err )
309
316
}
310
317
311
318
et := t .Elem ()
312
319
ret := reflect .MakeMap (t )
313
320
defer func () { v .Set (ret ) }()
314
321
322
+ // 当成默认值处理
323
+ if param .Tag .Key == "" {
324
+ if param .Tag .HasDef {
325
+ return nil
326
+ }
327
+ }
328
+
315
329
keys , err := p .SubKeys (param .Key )
316
330
if err != nil {
317
- return fmt . Errorf ( "%s: bind %s error, %w " , macro . FileLine (), param .Path , err )
331
+ return errutil . WrapError ( err , "bind path=%s type= %s error" , param .Path , v . Type (). String () )
318
332
}
319
333
320
334
for _ , key := range keys {
@@ -327,21 +341,20 @@ func bindMap(p readOnlyProperties, v reflect.Value, t reflect.Type, param BindPa
327
341
Key : subKey ,
328
342
Path : param .Path ,
329
343
}
330
- err = BindValue (p , e , et , subParam , filter )
331
- if err != nil {
332
- return fmt .Errorf ("%s: bind %s error, %w" , macro .FileLine (), param .Path , err )
344
+ if err = BindValue (p , e , et , subParam , filter ); err != nil {
345
+ return err // no wrap
333
346
}
334
347
ret .SetMapIndex (reflect .ValueOf (key ), e )
335
348
}
336
349
return nil
337
350
}
338
351
339
352
// bindStruct binds properties to a struct value.
340
- func bindStruct (p readOnlyProperties , v reflect.Value , t reflect.Type , param BindParam , filter Filter ) error {
353
+ func bindStruct (p ReadOnlyProperties , v reflect.Value , t reflect.Type , param BindParam , filter Filter ) error {
341
354
342
355
if param .Tag .HasDef && param .Tag .Def != "" {
343
356
err := errors .New ("struct can't have a non-empty default value" )
344
- return fmt .Errorf ("%s: bind %s error, %w" , macro . FileLine (), param . Path , err )
357
+ return fmt .Errorf ("bind path=%s type= %s error: %w" , param . Path , v . Type (). String () , err )
345
358
}
346
359
347
360
for i := 0 ; i < t .NumField (); i ++ {
@@ -359,7 +372,7 @@ func bindStruct(p readOnlyProperties, v reflect.Value, t reflect.Type, param Bin
359
372
360
373
if tag , ok := ft .Tag .Lookup ("value" ); ok {
361
374
if err := subParam .BindTag (tag , ft .Tag ); err != nil {
362
- return fmt . Errorf ( "%s: bind %s error, %w " , macro . FileLine (), param .Path , err )
375
+ return errutil . WrapError ( err , "bind path=%s type= %s error" , param .Path , v . Type (). String () )
363
376
}
364
377
if filter != nil {
365
378
ret , err := filter .Do (fv .Addr ().Interface (), subParam )
@@ -371,7 +384,7 @@ func bindStruct(p readOnlyProperties, v reflect.Value, t reflect.Type, param Bin
371
384
}
372
385
}
373
386
if err := BindValue (p , fv , ft .Type , subParam , filter ); err != nil {
374
- return fmt . Errorf ( "%s: bind %s error, %w" , macro . FileLine (), param . Path , err )
387
+ return err // no wrap
375
388
}
376
389
continue
377
390
}
@@ -382,12 +395,12 @@ func bindStruct(p readOnlyProperties, v reflect.Value, t reflect.Type, param Bin
382
395
continue
383
396
}
384
397
if err := bindStruct (p , fv , ft .Type , subParam , filter ); err != nil {
385
- return fmt . Errorf ( "%s: bind %s error, %w" , macro . FileLine (), param . Path , err )
398
+ return err // no wrap
386
399
}
387
400
continue
388
401
}
389
402
390
- if util .IsValueType (ft .Type ) {
403
+ if util .IsPropBindingTarget (ft .Type ) {
391
404
if subParam .Key == "" {
392
405
subParam .Key = ft .Name
393
406
} else {
@@ -396,33 +409,31 @@ func bindStruct(p readOnlyProperties, v reflect.Value, t reflect.Type, param Bin
396
409
subParam .Key = strings .ToLower (subParam .Key )
397
410
subParam .Key = strings .ReplaceAll (subParam .Key , "_" , "." )
398
411
if err := BindValue (p , fv , ft .Type , subParam , filter ); err != nil {
399
- return fmt . Errorf ( "%s: bind %s error, %w" , macro . FileLine (), param . Path , err )
412
+ return err // no wrap
400
413
}
401
414
}
402
415
}
403
416
return nil
404
417
}
405
418
406
419
// resolve returns property references processed property value.
407
- func resolve (p readOnlyProperties , param BindParam ) (string , error ) {
420
+ func resolve (p ReadOnlyProperties , param BindParam ) (string , error ) {
408
421
const defVal = "@@def@@"
409
- val := p .Get (param .Key , Def ( defVal ) )
422
+ val := p .Get (param .Key , defVal )
410
423
if val != defVal {
411
424
return resolveString (p , val )
412
425
}
413
426
if p .Has (param .Key ) {
414
- err := fmt .Errorf ("property %q isn't simple value" , param .Key )
415
- return "" , fmt .Errorf ("%s: resolve property %q error, %w" , macro .FileLine (), param .Key , err )
427
+ return "" , fmt .Errorf ("property key=%s isn't simple value" , param .Key )
416
428
}
417
429
if param .Tag .HasDef {
418
430
return resolveString (p , param .Tag .Def )
419
431
}
420
- err := fmt .Errorf ("property %q %w" , param .Key , ErrNotExist )
421
- return "" , fmt .Errorf ("%s: resolve property %q error, %w" , macro .FileLine (), param .Key , err )
432
+ return "" , fmt .Errorf ("property key=%s %w" , param .Key , ErrNotExist )
422
433
}
423
434
424
435
// resolveString returns property references processed string.
425
- func resolveString (p readOnlyProperties , s string ) (string , error ) {
436
+ func resolveString (p ReadOnlyProperties , s string ) (string , error ) {
426
437
427
438
var (
428
439
length = len (s )
@@ -456,20 +467,20 @@ func resolveString(p readOnlyProperties, s string) (string, error) {
456
467
457
468
if end < 0 || count > 0 {
458
469
err := ErrInvalidSyntax
459
- return "" , fmt .Errorf ("%s: resolve string %q error, %w" , macro . FileLine () , s , err )
470
+ return "" , fmt .Errorf ("resolve string %q error: %w" , s , err )
460
471
}
461
472
462
473
var param BindParam
463
474
_ = param .BindTag (s [start :end + 1 ], "" )
464
475
465
476
s1 , err := resolve (p , param )
466
477
if err != nil {
467
- return "" , fmt . Errorf ( "%s: resolve string %q error, %w " , macro . FileLine (), s , err )
478
+ return "" , errutil . WrapError ( err , " resolve string %q error" , s )
468
479
}
469
480
470
481
s2 , err := resolveString (p , s [end + 1 :])
471
482
if err != nil {
472
- return "" , fmt . Errorf ( "%s: resolve string %q error, %w " , macro . FileLine (), s , err )
483
+ return "" , errutil . WrapError ( err , " resolve string %q error" , s )
473
484
}
474
485
475
486
return s [:start ] + s1 + s2 , nil
0 commit comments