@@ -43,23 +43,18 @@ const (
43
43
)
44
44
45
45
var jsonPointableType = reflect .TypeOf (new (JSONPointable )).Elem ()
46
+ var jsonSetableType = reflect .TypeOf (new (JSONSetable )).Elem ()
46
47
47
48
// JSONPointable is an interface for structs to implement when they need to customize the
48
49
// json pointer process
49
50
type JSONPointable interface {
50
51
JSONLookup (string ) (interface {}, error )
51
52
}
52
53
53
- type implStruct struct {
54
- mode string // "SET" or "GET"
55
-
56
- inDocument interface {}
57
-
58
- setInValue interface {}
59
-
60
- getOutNode interface {}
61
- getOutKind reflect.Kind
62
- outError error
54
+ // JSONSetable is an interface for structs to implement when they need to customize the
55
+ // json pointer process
56
+ type JSONSetable interface {
57
+ JSONSet (string , interface {}) error
63
58
}
64
59
65
60
// New creates a new json pointer for the given string
@@ -100,15 +95,25 @@ func (p *Pointer) Get(document interface{}) (interface{}, reflect.Kind, error) {
100
95
return p .get (document , swag .DefaultJSONNameProvider )
101
96
}
102
97
98
+ // Set uses the pointer to set a value from a JSON document
99
+ func (p * Pointer ) Set (document interface {}, value interface {}) (interface {}, error ) {
100
+ return document , p .set (document , value , swag .DefaultJSONNameProvider )
101
+ }
102
+
103
103
// GetForToken gets a value for a json pointer token 1 level deep
104
104
func GetForToken (document interface {}, decodedToken string ) (interface {}, reflect.Kind , error ) {
105
105
return getSingleImpl (document , decodedToken , swag .DefaultJSONNameProvider )
106
106
}
107
107
108
+ // SetForToken gets a value for a json pointer token 1 level deep
109
+ func SetForToken (document interface {}, decodedToken string , value interface {}) (interface {}, error ) {
110
+ return document , setSingleImpl (document , value , decodedToken , swag .DefaultJSONNameProvider )
111
+ }
112
+
108
113
func getSingleImpl (node interface {}, decodedToken string , nameProvider * swag.NameProvider ) (interface {}, reflect.Kind , error ) {
109
- kind := reflect .Invalid
110
114
rValue := reflect .Indirect (reflect .ValueOf (node ))
111
- kind = rValue .Kind ()
115
+ kind := rValue .Kind ()
116
+
112
117
switch kind {
113
118
114
119
case reflect .Struct :
@@ -129,6 +134,7 @@ func getSingleImpl(node interface{}, decodedToken string, nameProvider *swag.Nam
129
134
case reflect .Map :
130
135
kv := reflect .ValueOf (decodedToken )
131
136
mv := rValue .MapIndex (kv )
137
+
132
138
if mv .IsValid () && ! swag .IsZero (mv ) {
133
139
return mv .Interface (), kind , nil
134
140
}
@@ -141,7 +147,7 @@ func getSingleImpl(node interface{}, decodedToken string, nameProvider *swag.Nam
141
147
}
142
148
sLength := rValue .Len ()
143
149
if tokenIndex < 0 || tokenIndex >= sLength {
144
- return nil , kind , fmt .Errorf ("index out of bounds array[0,%d] index '%d'" , sLength , tokenIndex )
150
+ return nil , kind , fmt .Errorf ("index out of bounds array[0,%d] index '%d'" , sLength - 1 , tokenIndex )
145
151
}
146
152
147
153
elem := rValue .Index (tokenIndex )
@@ -153,6 +159,57 @@ func getSingleImpl(node interface{}, decodedToken string, nameProvider *swag.Nam
153
159
154
160
}
155
161
162
+ func setSingleImpl (node , data interface {}, decodedToken string , nameProvider * swag.NameProvider ) error {
163
+ rValue := reflect .Indirect (reflect .ValueOf (node ))
164
+ switch rValue .Kind () {
165
+
166
+ case reflect .Struct :
167
+ if ns , ok := node .(JSONSetable ); ok { // pointer impl
168
+ return ns .JSONSet (decodedToken , data )
169
+ }
170
+
171
+ if rValue .Type ().Implements (jsonSetableType ) {
172
+ return node .(JSONSetable ).JSONSet (decodedToken , data )
173
+ }
174
+
175
+ nm , ok := nameProvider .GetGoNameForType (rValue .Type (), decodedToken )
176
+ if ! ok {
177
+ return fmt .Errorf ("object has no field %q" , decodedToken )
178
+ }
179
+ fld := rValue .FieldByName (nm )
180
+ if fld .IsValid () {
181
+ fld .Set (reflect .ValueOf (data ))
182
+ }
183
+ return nil
184
+
185
+ case reflect .Map :
186
+ kv := reflect .ValueOf (decodedToken )
187
+ rValue .SetMapIndex (kv , reflect .ValueOf (data ))
188
+ return nil
189
+
190
+ case reflect .Slice :
191
+ tokenIndex , err := strconv .Atoi (decodedToken )
192
+ if err != nil {
193
+ return err
194
+ }
195
+ sLength := rValue .Len ()
196
+ if tokenIndex < 0 || tokenIndex >= sLength {
197
+ return fmt .Errorf ("index out of bounds array[0,%d] index '%d'" , sLength , tokenIndex )
198
+ }
199
+
200
+ elem := rValue .Index (tokenIndex )
201
+ if ! elem .CanSet () {
202
+ return fmt .Errorf ("can't set slice index %s to %v" , decodedToken , data )
203
+ }
204
+ elem .Set (reflect .ValueOf (data ))
205
+ return nil
206
+
207
+ default :
208
+ return fmt .Errorf ("invalid token reference %q" , decodedToken )
209
+ }
210
+
211
+ }
212
+
156
213
func (p * Pointer ) get (node interface {}, nameProvider * swag.NameProvider ) (interface {}, reflect.Kind , error ) {
157
214
158
215
if nameProvider == nil {
@@ -184,6 +241,101 @@ func (p *Pointer) get(node interface{}, nameProvider *swag.NameProvider) (interf
184
241
return node , kind , nil
185
242
}
186
243
244
+ func (p * Pointer ) set (node , data interface {}, nameProvider * swag.NameProvider ) error {
245
+ knd := reflect .ValueOf (node ).Kind ()
246
+
247
+ if knd != reflect .Ptr && knd != reflect .Struct && knd != reflect .Map && knd != reflect .Slice && knd != reflect .Array {
248
+ return fmt .Errorf ("only structs, pointers, maps and slices are supported for setting values" )
249
+ }
250
+
251
+ if nameProvider == nil {
252
+ nameProvider = swag .DefaultJSONNameProvider
253
+ }
254
+
255
+ // Full document when empty
256
+ if len (p .referenceTokens ) == 0 {
257
+ return nil
258
+ }
259
+
260
+ lastI := len (p .referenceTokens ) - 1
261
+ for i , token := range p .referenceTokens {
262
+ isLastToken := i == lastI
263
+ decodedToken := Unescape (token )
264
+
265
+ if isLastToken {
266
+
267
+ return setSingleImpl (node , data , decodedToken , nameProvider )
268
+ }
269
+
270
+ rValue := reflect .Indirect (reflect .ValueOf (node ))
271
+ kind := rValue .Kind ()
272
+
273
+ switch kind {
274
+
275
+ case reflect .Struct :
276
+ if rValue .Type ().Implements (jsonPointableType ) {
277
+ r , err := node .(JSONPointable ).JSONLookup (decodedToken )
278
+ if err != nil {
279
+ return err
280
+ }
281
+ fld := reflect .ValueOf (r )
282
+ if fld .CanAddr () && fld .Kind () != reflect .Interface && fld .Kind () != reflect .Map && fld .Kind () != reflect .Slice && fld .Kind () != reflect .Ptr {
283
+ node = fld .Addr ().Interface ()
284
+ continue
285
+ }
286
+ node = r
287
+ continue
288
+ }
289
+ nm , ok := nameProvider .GetGoNameForType (rValue .Type (), decodedToken )
290
+ if ! ok {
291
+ return fmt .Errorf ("object has no field %q" , decodedToken )
292
+ }
293
+ fld := rValue .FieldByName (nm )
294
+ if fld .CanAddr () && fld .Kind () != reflect .Interface && fld .Kind () != reflect .Map && fld .Kind () != reflect .Slice && fld .Kind () != reflect .Ptr {
295
+ node = fld .Addr ().Interface ()
296
+ continue
297
+ }
298
+ node = fld .Interface ()
299
+
300
+ case reflect .Map :
301
+ kv := reflect .ValueOf (decodedToken )
302
+ mv := rValue .MapIndex (kv )
303
+
304
+ if ! mv .IsValid () {
305
+ return fmt .Errorf ("object has no key %q" , decodedToken )
306
+ }
307
+ if mv .CanAddr () && mv .Kind () != reflect .Interface && mv .Kind () != reflect .Map && mv .Kind () != reflect .Slice && mv .Kind () != reflect .Ptr {
308
+ node = mv .Addr ().Interface ()
309
+ continue
310
+ }
311
+ node = mv .Interface ()
312
+
313
+ case reflect .Slice :
314
+ tokenIndex , err := strconv .Atoi (decodedToken )
315
+ if err != nil {
316
+ return err
317
+ }
318
+ sLength := rValue .Len ()
319
+ if tokenIndex < 0 || tokenIndex >= sLength {
320
+ return fmt .Errorf ("index out of bounds array[0,%d] index '%d'" , sLength , tokenIndex )
321
+ }
322
+
323
+ elem := rValue .Index (tokenIndex )
324
+ if elem .CanAddr () && elem .Kind () != reflect .Interface && elem .Kind () != reflect .Map && elem .Kind () != reflect .Slice && elem .Kind () != reflect .Ptr {
325
+ node = elem .Addr ().Interface ()
326
+ continue
327
+ }
328
+ node = elem .Interface ()
329
+
330
+ default :
331
+ return fmt .Errorf ("invalid token reference %q" , decodedToken )
332
+ }
333
+
334
+ }
335
+
336
+ return nil
337
+ }
338
+
187
339
// DecodedTokens returns the decoded tokens
188
340
func (p * Pointer ) DecodedTokens () []string {
189
341
result := make ([]string , 0 , len (p .referenceTokens ))
0 commit comments