9
9
package org .elasticsearch .common .xcontent ;
10
10
11
11
import org .elasticsearch .common .ParseField ;
12
+ import org .elasticsearch .common .compatibility .RestApiCompatibleVersion ;
12
13
import org .elasticsearch .common .xcontent .ObjectParser .NamedObjectParser ;
13
14
import org .elasticsearch .common .xcontent .ObjectParser .ValueType ;
14
15
15
16
import java .io .IOException ;
16
17
import java .util .ArrayList ;
18
+ import java .util .Collections ;
19
+ import java .util .EnumMap ;
17
20
import java .util .List ;
21
+ import java .util .Map ;
18
22
import java .util .function .BiConsumer ;
19
23
import java .util .function .BiFunction ;
20
24
import java .util .function .Consumer ;
21
25
import java .util .function .Function ;
26
+ import java .util .stream .Collectors ;
22
27
23
28
/**
24
29
* Like {@link ObjectParser} but works with objects that have constructors whose arguments are mixed in with its other settings. Queries are
@@ -82,7 +87,8 @@ public final class ConstructingObjectParser<Value, Context> extends AbstractObje
82
87
/**
83
88
* List of constructor names used for generating the error message if not all arrive.
84
89
*/
85
- private final List <ConstructorArgInfo > constructorArgInfos = new ArrayList <>();
90
+ private final Map <RestApiCompatibleVersion , List <ConstructorArgInfo >> constructorArgInfos =
91
+ new EnumMap <>(RestApiCompatibleVersion .class );
86
92
private final ObjectParser <Target , Context > objectParser ;
87
93
private final BiFunction <Object [], Context , Value > builder ;
88
94
/**
@@ -205,8 +211,8 @@ public <T> void declareField(BiConsumer<Value, T> consumer, ContextParser<Contex
205
211
* constructor in the argument list so we don't need to do any fancy
206
212
* or expensive lookups whenever the constructor args come in.
207
213
*/
208
- int position = addConstructorArg (consumer , parseField );
209
- objectParser .declareField ((target , v ) -> target .constructorArg (position , v ), parser , parseField , type );
214
+ Map < RestApiCompatibleVersion , Integer > positions = addConstructorArg (consumer , parseField );
215
+ objectParser .declareField ((target , v ) -> target .constructorArg (positions , v ), parser , parseField , type );
210
216
} else {
211
217
numberOfFields += 1 ;
212
218
objectParser .declareField (queueingConsumer (consumer , parseField ), parser , parseField , type );
@@ -234,8 +240,8 @@ public <T> void declareNamedObject(BiConsumer<Value, T> consumer, NamedObjectPar
234
240
* constructor in the argument list so we don't need to do any fancy
235
241
* or expensive lookups whenever the constructor args come in.
236
242
*/
237
- int position = addConstructorArg (consumer , parseField );
238
- objectParser .declareNamedObject ((target , v ) -> target .constructorArg (position , v ), namedObjectParser , parseField );
243
+ Map < RestApiCompatibleVersion , Integer > positions = addConstructorArg (consumer , parseField );
244
+ objectParser .declareNamedObject ((target , v ) -> target .constructorArg (positions , v ), namedObjectParser , parseField );
239
245
} else {
240
246
numberOfFields += 1 ;
241
247
objectParser .declareNamedObject (queueingConsumer (consumer , parseField ), namedObjectParser , parseField );
@@ -264,8 +270,8 @@ public <T> void declareNamedObjects(BiConsumer<Value, List<T>> consumer, NamedOb
264
270
* constructor in the argument list so we don't need to do any fancy
265
271
* or expensive lookups whenever the constructor args come in.
266
272
*/
267
- int position = addConstructorArg (consumer , parseField );
268
- objectParser .declareNamedObjects ((target , v ) -> target .constructorArg (position , v ), namedObjectParser , parseField );
273
+ Map < RestApiCompatibleVersion , Integer > positions = addConstructorArg (consumer , parseField );
274
+ objectParser .declareNamedObjects ((target , v ) -> target .constructorArg (positions , v ), namedObjectParser , parseField );
269
275
} else {
270
276
numberOfFields += 1 ;
271
277
objectParser .declareNamedObjects (queueingConsumer (consumer , parseField ), namedObjectParser , parseField );
@@ -296,18 +302,21 @@ public <T> void declareNamedObjects(BiConsumer<Value, List<T>> consumer, NamedOb
296
302
* constructor in the argument list so we don't need to do any fancy
297
303
* or expensive lookups whenever the constructor args come in.
298
304
*/
299
- int position = addConstructorArg (consumer , parseField );
300
- objectParser .declareNamedObjects ((target , v ) -> target .constructorArg (position , v ), namedObjectParser ,
301
- wrapOrderedModeCallBack (orderedModeCallback ), parseField );
305
+ Map < RestApiCompatibleVersion , Integer > positions = addConstructorArg (consumer , parseField );
306
+ objectParser .declareNamedObjects ((target , v ) -> target .constructorArg (positions , v ), namedObjectParser ,
307
+ wrapOrderedModeCallBack (orderedModeCallback ), parseField );
302
308
} else {
303
309
numberOfFields += 1 ;
304
310
objectParser .declareNamedObjects (queueingConsumer (consumer , parseField ), namedObjectParser ,
305
- wrapOrderedModeCallBack (orderedModeCallback ), parseField );
311
+ wrapOrderedModeCallBack (orderedModeCallback ), parseField );
306
312
}
307
313
}
308
314
309
315
int getNumberOfFields () {
310
- return this .constructorArgInfos .size ();
316
+ assert this .constructorArgInfos .get (RestApiCompatibleVersion .currentVersion ()).size ()
317
+ == this .constructorArgInfos .get (RestApiCompatibleVersion .minimumSupported ()).size () :
318
+ "Constructors must have same number of arguments per all compatible versions" ;
319
+ return this .constructorArgInfos .get (RestApiCompatibleVersion .currentVersion ()).size ();
311
320
}
312
321
313
322
/**
@@ -324,11 +333,17 @@ private boolean isConstructorArg(BiConsumer<?, ?> consumer) {
324
333
* @param parseField Parse field
325
334
* @return The argument position
326
335
*/
327
- private int addConstructorArg (BiConsumer <?, ?> consumer , ParseField parseField ) {
328
- int position = constructorArgInfos . size ();
336
+ private Map < RestApiCompatibleVersion , Integer > addConstructorArg (BiConsumer <?, ?> consumer , ParseField parseField ) {
337
+
329
338
boolean required = consumer == REQUIRED_CONSTRUCTOR_ARG_MARKER ;
330
- constructorArgInfos .add (new ConstructorArgInfo (parseField , required ));
331
- return position ;
339
+ for (RestApiCompatibleVersion restApiCompatibleVersion : parseField .getRestApiCompatibleVersions ()) {
340
+
341
+ constructorArgInfos .computeIfAbsent (restApiCompatibleVersion , (v )-> new ArrayList <>())
342
+ .add (new ConstructorArgInfo (parseField , required ));
343
+ }
344
+
345
+ //calculate the positions for the arguments
346
+ return constructorArgInfos .entrySet ().stream ().collect (Collectors .toMap (Map .Entry ::getKey , e -> e .getValue ().size ()));
332
347
}
333
348
334
349
@ Override
@@ -398,7 +413,7 @@ private class Target {
398
413
/**
399
414
* Array of constructor args to be passed to the {@link ConstructingObjectParser#builder}.
400
415
*/
401
- private final Object [] constructorArgs = new Object [ constructorArgInfos . size ()] ;
416
+ private final Object [] constructorArgs ;
402
417
/**
403
418
* The parser this class is working against. We store it here so we can fetch it conveniently when queueing fields to lookup the
404
419
* location of each field so that we can give a useful error message when replaying the queue.
@@ -437,15 +452,18 @@ private class Target {
437
452
Target (XContentParser parser , Context context ) {
438
453
this .parser = parser ;
439
454
this .context = context ;
455
+ this .constructorArgs = new Object [constructorArgInfos
456
+ .getOrDefault (parser .getRestApiCompatibleVersion (), Collections .emptyList ()).size ()];
440
457
}
441
458
442
459
/**
443
460
* Set a constructor argument and build the target object if all constructor arguments have arrived.
444
461
*/
445
- private void constructorArg (int position , Object value ) {
462
+ private void constructorArg (Map <RestApiCompatibleVersion , Integer > positions , Object value ) {
463
+ int position = positions .get (parser .getRestApiCompatibleVersion ()) - 1 ;
446
464
constructorArgs [position ] = value ;
447
465
constructorArgsCollected ++;
448
- if (constructorArgsCollected == constructorArgInfos .size ()) {
466
+ if (constructorArgsCollected == constructorArgInfos .get ( parser . getRestApiCompatibleVersion ()). size ()) {
449
467
buildTarget ();
450
468
}
451
469
}
@@ -480,7 +498,7 @@ private Value finish() {
480
498
StringBuilder message = null ;
481
499
for (int i = 0 ; i < constructorArgs .length ; i ++) {
482
500
if (constructorArgs [i ] != null ) continue ;
483
- ConstructorArgInfo arg = constructorArgInfos .get (i );
501
+ ConstructorArgInfo arg = constructorArgInfos .get (parser . getRestApiCompatibleVersion ()). get ( i );
484
502
if (false == arg .required ) continue ;
485
503
if (message == null ) {
486
504
message = new StringBuilder ("Required [" ).append (arg .field );
0 commit comments