|
@@ -9,16 +9,21 @@
|
|
|
package org.elasticsearch.common.xcontent;
|
|
|
|
|
|
import org.elasticsearch.common.ParseField;
|
|
|
+import org.elasticsearch.common.compatibility.RestApiCompatibleVersion;
|
|
|
import org.elasticsearch.common.xcontent.ObjectParser.NamedObjectParser;
|
|
|
import org.elasticsearch.common.xcontent.ObjectParser.ValueType;
|
|
|
|
|
|
import java.io.IOException;
|
|
|
import java.util.ArrayList;
|
|
|
+import java.util.Collections;
|
|
|
+import java.util.EnumMap;
|
|
|
import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
import java.util.function.BiConsumer;
|
|
|
import java.util.function.BiFunction;
|
|
|
import java.util.function.Consumer;
|
|
|
import java.util.function.Function;
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
|
/**
|
|
|
* 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
|
|
|
/**
|
|
|
* List of constructor names used for generating the error message if not all arrive.
|
|
|
*/
|
|
|
- private final List<ConstructorArgInfo> constructorArgInfos = new ArrayList<>();
|
|
|
+ private final Map<RestApiCompatibleVersion, List<ConstructorArgInfo>> constructorArgInfos =
|
|
|
+ new EnumMap<>(RestApiCompatibleVersion.class);
|
|
|
private final ObjectParser<Target, Context> objectParser;
|
|
|
private final BiFunction<Object[], Context, Value> builder;
|
|
|
/**
|
|
@@ -205,8 +211,8 @@ public final class ConstructingObjectParser<Value, Context> extends AbstractObje
|
|
|
* constructor in the argument list so we don't need to do any fancy
|
|
|
* or expensive lookups whenever the constructor args come in.
|
|
|
*/
|
|
|
- int position = addConstructorArg(consumer, parseField);
|
|
|
- objectParser.declareField((target, v) -> target.constructorArg(position, v), parser, parseField, type);
|
|
|
+ Map<RestApiCompatibleVersion, Integer> positions = addConstructorArg(consumer, parseField);
|
|
|
+ objectParser.declareField((target, v) -> target.constructorArg(positions, v), parser, parseField, type);
|
|
|
} else {
|
|
|
numberOfFields += 1;
|
|
|
objectParser.declareField(queueingConsumer(consumer, parseField), parser, parseField, type);
|
|
@@ -234,8 +240,8 @@ public final class ConstructingObjectParser<Value, Context> extends AbstractObje
|
|
|
* constructor in the argument list so we don't need to do any fancy
|
|
|
* or expensive lookups whenever the constructor args come in.
|
|
|
*/
|
|
|
- int position = addConstructorArg(consumer, parseField);
|
|
|
- objectParser.declareNamedObject((target, v) -> target.constructorArg(position, v), namedObjectParser, parseField);
|
|
|
+ Map<RestApiCompatibleVersion, Integer> positions = addConstructorArg(consumer, parseField);
|
|
|
+ objectParser.declareNamedObject((target, v) -> target.constructorArg(positions, v), namedObjectParser, parseField);
|
|
|
} else {
|
|
|
numberOfFields += 1;
|
|
|
objectParser.declareNamedObject(queueingConsumer(consumer, parseField), namedObjectParser, parseField);
|
|
@@ -264,8 +270,8 @@ public final class ConstructingObjectParser<Value, Context> extends AbstractObje
|
|
|
* constructor in the argument list so we don't need to do any fancy
|
|
|
* or expensive lookups whenever the constructor args come in.
|
|
|
*/
|
|
|
- int position = addConstructorArg(consumer, parseField);
|
|
|
- objectParser.declareNamedObjects((target, v) -> target.constructorArg(position, v), namedObjectParser, parseField);
|
|
|
+ Map<RestApiCompatibleVersion, Integer> positions = addConstructorArg(consumer, parseField);
|
|
|
+ objectParser.declareNamedObjects((target, v) -> target.constructorArg(positions, v), namedObjectParser, parseField);
|
|
|
} else {
|
|
|
numberOfFields += 1;
|
|
|
objectParser.declareNamedObjects(queueingConsumer(consumer, parseField), namedObjectParser, parseField);
|
|
@@ -296,18 +302,21 @@ public final class ConstructingObjectParser<Value, Context> extends AbstractObje
|
|
|
* constructor in the argument list so we don't need to do any fancy
|
|
|
* or expensive lookups whenever the constructor args come in.
|
|
|
*/
|
|
|
- int position = addConstructorArg(consumer, parseField);
|
|
|
- objectParser.declareNamedObjects((target, v) -> target.constructorArg(position, v), namedObjectParser,
|
|
|
- wrapOrderedModeCallBack(orderedModeCallback), parseField);
|
|
|
+ Map<RestApiCompatibleVersion, Integer> positions = addConstructorArg(consumer, parseField);
|
|
|
+ objectParser.declareNamedObjects((target, v) -> target.constructorArg(positions, v), namedObjectParser,
|
|
|
+ wrapOrderedModeCallBack(orderedModeCallback), parseField);
|
|
|
} else {
|
|
|
numberOfFields += 1;
|
|
|
objectParser.declareNamedObjects(queueingConsumer(consumer, parseField), namedObjectParser,
|
|
|
- wrapOrderedModeCallBack(orderedModeCallback), parseField);
|
|
|
+ wrapOrderedModeCallBack(orderedModeCallback), parseField);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
int getNumberOfFields() {
|
|
|
- return this.constructorArgInfos.size();
|
|
|
+ assert this.constructorArgInfos.get(RestApiCompatibleVersion.currentVersion()).size()
|
|
|
+ == this.constructorArgInfos.get(RestApiCompatibleVersion.minimumSupported()).size() :
|
|
|
+ "Constructors must have same number of arguments per all compatible versions";
|
|
|
+ return this.constructorArgInfos.get(RestApiCompatibleVersion.currentVersion()).size();
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -324,11 +333,17 @@ public final class ConstructingObjectParser<Value, Context> extends AbstractObje
|
|
|
* @param parseField Parse field
|
|
|
* @return The argument position
|
|
|
*/
|
|
|
- private int addConstructorArg(BiConsumer<?, ?> consumer, ParseField parseField) {
|
|
|
- int position = constructorArgInfos.size();
|
|
|
+ private Map<RestApiCompatibleVersion, Integer> addConstructorArg(BiConsumer<?, ?> consumer, ParseField parseField) {
|
|
|
+
|
|
|
boolean required = consumer == REQUIRED_CONSTRUCTOR_ARG_MARKER;
|
|
|
- constructorArgInfos.add(new ConstructorArgInfo(parseField, required));
|
|
|
- return position;
|
|
|
+ for (RestApiCompatibleVersion restApiCompatibleVersion : parseField.getRestApiCompatibleVersions()) {
|
|
|
+
|
|
|
+ constructorArgInfos.computeIfAbsent(restApiCompatibleVersion, (v)-> new ArrayList<>())
|
|
|
+ .add(new ConstructorArgInfo(parseField, required));
|
|
|
+ }
|
|
|
+
|
|
|
+ //calculate the positions for the arguments
|
|
|
+ return constructorArgInfos.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().size()));
|
|
|
}
|
|
|
|
|
|
@Override
|
|
@@ -398,7 +413,7 @@ public final class ConstructingObjectParser<Value, Context> extends AbstractObje
|
|
|
/**
|
|
|
* Array of constructor args to be passed to the {@link ConstructingObjectParser#builder}.
|
|
|
*/
|
|
|
- private final Object[] constructorArgs = new Object[constructorArgInfos.size()];
|
|
|
+ private final Object[] constructorArgs;
|
|
|
/**
|
|
|
* The parser this class is working against. We store it here so we can fetch it conveniently when queueing fields to lookup the
|
|
|
* location of each field so that we can give a useful error message when replaying the queue.
|
|
@@ -437,15 +452,18 @@ public final class ConstructingObjectParser<Value, Context> extends AbstractObje
|
|
|
Target(XContentParser parser, Context context) {
|
|
|
this.parser = parser;
|
|
|
this.context = context;
|
|
|
+ this.constructorArgs = new Object[constructorArgInfos
|
|
|
+ .getOrDefault(parser.getRestApiCompatibleVersion(), Collections.emptyList()).size()];
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Set a constructor argument and build the target object if all constructor arguments have arrived.
|
|
|
*/
|
|
|
- private void constructorArg(int position, Object value) {
|
|
|
+ private void constructorArg(Map<RestApiCompatibleVersion, Integer> positions, Object value) {
|
|
|
+ int position = positions.get(parser.getRestApiCompatibleVersion()) - 1;
|
|
|
constructorArgs[position] = value;
|
|
|
constructorArgsCollected++;
|
|
|
- if (constructorArgsCollected == constructorArgInfos.size()) {
|
|
|
+ if (constructorArgsCollected == constructorArgInfos.get(parser.getRestApiCompatibleVersion()).size()) {
|
|
|
buildTarget();
|
|
|
}
|
|
|
}
|
|
@@ -480,7 +498,7 @@ public final class ConstructingObjectParser<Value, Context> extends AbstractObje
|
|
|
StringBuilder message = null;
|
|
|
for (int i = 0; i < constructorArgs.length; i++) {
|
|
|
if (constructorArgs[i] != null) continue;
|
|
|
- ConstructorArgInfo arg = constructorArgInfos.get(i);
|
|
|
+ ConstructorArgInfo arg = constructorArgInfos.get(parser.getRestApiCompatibleVersion()).get(i);
|
|
|
if (false == arg.required) continue;
|
|
|
if (message == null) {
|
|
|
message = new StringBuilder("Required [").append(arg.field);
|