Class ConstructingObjectParser<Value,Context>
- java.lang.Object
-
- org.elasticsearch.common.xcontent.AbstractObjectParser<Value,Context>
-
- org.elasticsearch.common.xcontent.ConstructingObjectParser<Value,Context>
-
- All Implemented Interfaces:
java.util.function.BiFunction<XContentParser,Context,Value>
,ContextParser<Context,Value>
public final class ConstructingObjectParser<Value,Context> extends AbstractObjectParser<Value,Context>
LikeObjectParser
but works with objects that have constructors whose arguments are mixed in with its other settings. Queries are like this, for exampleids
requirestypes
but always parses thevalues
field on the same level. If this doesn't sounds like what you want to parse have a look atObjectParser.declareNamedObjects(BiConsumer, ObjectParser.NamedObjectParser, Consumer, ParseField)
which solves a slightly different but similar sounding problem.Anyway, ConstructingObjectParser parses the fields in the order that they are in the XContent, collecting constructor arguments and parsing and queueing normal fields until all constructor arguments are parsed. Then it builds the target object and replays the queued fields. Any fields that come in after the last constructor arguments are parsed and immediately applied to the target object just like ObjectParser.
Declaring a ConstructingObjectParser is intentionally quite similar to declaring an ObjectParser. The only differences being that constructor arguments are declared with the consumer returned by the static
constructorArg()
method and that ConstructingObjectParser's constructor takes a lambda that must build the target object from a list of constructor arguments:private static final ConstructingObjectParser<Thing, SomeContext> PARSER = new ConstructingObjectParser<>("thing", a -> new Thing((String) a[0], (String) a[1], (Integer) a[2])); static { PARSER.declareString(constructorArg(), new ParseField("animal")); PARSER.declareString(constructorArg(), new ParseField("vegetable")); PARSER.declareInt(optionalConstructorArg(), new ParseField("mineral")); PARSER.declareInt(Thing::setFruit, new ParseField("fruit")); PARSER.declareInt(Thing::setBug, new ParseField("bug")); }
This does add some overhead compared to just using ObjectParser directly. On a 2.2 GHz Intel Core i7 MacBook Air running on battery power in a reasonably unscientific microbenchmark it is about 100 microseconds for a reasonably large object, less if the constructor arguments are first. On this platform with the same microbenchmarks just creating the XContentParser is around 900 microseconds and using {#linkplain ObjectParser} directly adds another 300 or so microseconds. In the best case ConstructingObjectParser allocates two additional objects per parse compared to {#linkplain ObjectParser}. In the worst case it allocates
3 + 2 * param_count
objects per parse. If this overhead is too much for you then feel free to have ObjectParser parse a secondary object and have that one call the target object's constructor. That ought to be rare though.Note: if optional constructor arguments aren't specified then the number of allocations is always the worst case.
-
-
Constructor Summary
Constructors Constructor Description ConstructingObjectParser(java.lang.String name, boolean ignoreUnknownFields, java.util.function.BiFunction<java.lang.Object[],Context,Value> builder)
Build the parser.ConstructingObjectParser(java.lang.String name, boolean ignoreUnknownFields, java.util.function.Function<java.lang.Object[],Value> builder)
Build the parser.ConstructingObjectParser(java.lang.String name, java.util.function.Function<java.lang.Object[],Value> builder)
Build the parser.
-
Method Summary
Modifier and Type Method Description Value
apply(XContentParser parser, Context context)
Call this to do the actual parsing.static <Value,FieldT>
java.util.function.BiConsumer<Value,FieldT>constructorArg()
Pass the BiConsumer this returns the declare methods to declare a required constructor argument.<T> void
declareField(java.util.function.BiConsumer<Value,T> consumer, ContextParser<Context,T> parser, ParseField parseField, ObjectParser.ValueType type)
Declare some field.<T> void
declareNamedObjects(java.util.function.BiConsumer<Value,java.util.List<T>> consumer, ObjectParser.NamedObjectParser<T,Context> namedObjectParser, java.util.function.Consumer<Value> orderedModeCallback, ParseField parseField)
Declares named objects in the style of highlighting's field element.<T> void
declareNamedObjects(java.util.function.BiConsumer<Value,java.util.List<T>> consumer, ObjectParser.NamedObjectParser<T,Context> namedObjectParser, ParseField parseField)
Declares named objects in the style of aggregations.java.lang.String
getName()
static <Value,FieldT>
java.util.function.BiConsumer<Value,FieldT>optionalConstructorArg()
Pass the BiConsumer this returns the declare methods to declare an optional constructor argument.Value
parse(XContentParser parser, Context context)
-
Methods inherited from class org.elasticsearch.common.xcontent.AbstractObjectParser
declareBoolean, declareDouble, declareDoubleArray, declareField, declareFieldArray, declareFloat, declareFloatArray, declareInt, declareIntArray, declareLong, declareLongArray, declareObject, declareObjectArray, declareString, declareStringArray, declareStringOrNull
-
-
-
-
Constructor Detail
-
ConstructingObjectParser
public ConstructingObjectParser(java.lang.String name, java.util.function.Function<java.lang.Object[],Value> builder)
Build the parser.- Parameters:
name
- The name given to the delegate ObjectParser for error identification. Use what you'd use if the object worked with ObjectParser.builder
- A function that builds the object from an array of Objects. Declare this inline with the parser, casting the elements of the array to the arguments so they work with your favorite constructor. The objects in the array will be in the same order that you declared theconstructorArg()
s and none will be null. If any of the constructor arguments aren't defined in the XContent then parsing will throw an error. We use an array here rather than aMap<String, Object>
to save on allocations.
-
ConstructingObjectParser
public ConstructingObjectParser(java.lang.String name, boolean ignoreUnknownFields, java.util.function.Function<java.lang.Object[],Value> builder)
Build the parser.- Parameters:
name
- The name given to the delegate ObjectParser for error identification. Use what you'd use if the object worked with ObjectParser.ignoreUnknownFields
- Should this parser ignore unknown fields? This should generally be set to true only when parsing responses from external systems, never when parsing requests from users.builder
- A function that builds the object from an array of Objects. Declare this inline with the parser, casting the elements of the array to the arguments so they work with your favorite constructor. The objects in the array will be in the same order that you declared theconstructorArg()
s and none will be null. If any of the constructor arguments aren't defined in the XContent then parsing will throw an error. We use an array here rather than aMap<String, Object>
to save on allocations.
-
ConstructingObjectParser
public ConstructingObjectParser(java.lang.String name, boolean ignoreUnknownFields, java.util.function.BiFunction<java.lang.Object[],Context,Value> builder)
Build the parser.- Parameters:
name
- The name given to the delegate ObjectParser for error identification. Use what you'd use if the object worked with ObjectParser.ignoreUnknownFields
- Should this parser ignore unknown fields? This should generally be set to true only when parsing responses from external systems, never when parsing requests from users.builder
- A binary function that builds the object from an array of Objects and the parser context. Declare this inline with the parser, casting the elements of the array to the arguments so they work with your favorite constructor. The objects in the array will be in the same order that you declared theconstructorArg()
s and none will be null. The second argument is the value of the context provided to theparse function
. If any of the constructor arguments aren't defined in the XContent then parsing will throw an error. We use an array here rather than aMap<String, Object>
to save on allocations.
-
-
Method Detail
-
apply
public Value apply(XContentParser parser, Context context)
Call this to do the actual parsing. This implementsBiFunction
for conveniently integrating with ObjectParser.
-
parse
public Value parse(XContentParser parser, Context context) throws java.io.IOException
- Throws:
java.io.IOException
-
constructorArg
public static <Value,FieldT> java.util.function.BiConsumer<Value,FieldT> constructorArg()
Pass the BiConsumer this returns the declare methods to declare a required constructor argument. See this class's javadoc for an example. The order in which these are declared matters: it is the order that they come in the array passed tobuilder
and the order that missing arguments are reported to the user if any are missing. When all of these parameters are parsed from the XContentParser the target object is immediately built.
-
optionalConstructorArg
public static <Value,FieldT> java.util.function.BiConsumer<Value,FieldT> optionalConstructorArg()
Pass the BiConsumer this returns the declare methods to declare an optional constructor argument. See this class's javadoc for an example. The order in which these are declared matters: it is the order that they come in the array passed tobuilder
and the order that missing arguments are reported to the user if any are missing. When all of these parameters are parsed from the XContentParser the target object is immediately built.
-
declareField
public <T> void declareField(java.util.function.BiConsumer<Value,T> consumer, ContextParser<Context,T> parser, ParseField parseField, ObjectParser.ValueType type)
Description copied from class:AbstractObjectParser
Declare some field. Usually it is easier to useAbstractObjectParser.declareString(BiConsumer, ParseField)
orAbstractObjectParser.declareObject(BiConsumer, ContextParser, ParseField)
rather than call this directly.- Specified by:
declareField
in classAbstractObjectParser<Value,Context>
-
declareNamedObjects
public <T> void declareNamedObjects(java.util.function.BiConsumer<Value,java.util.List<T>> consumer, ObjectParser.NamedObjectParser<T,Context> namedObjectParser, ParseField parseField)
Description copied from class:AbstractObjectParser
Declares named objects in the style of aggregations. These are named inside and object like this:{ "aggregations": { "name_1": { "aggregation_type": {} }, "name_2": { "aggregation_type": {} }, "name_3": { "aggregation_type": {} } } } }
- Specified by:
declareNamedObjects
in classAbstractObjectParser<Value,Context>
- Parameters:
consumer
- sets the values once they have been parsednamedObjectParser
- parses each named objectparseField
- the field to parse
-
declareNamedObjects
public <T> void declareNamedObjects(java.util.function.BiConsumer<Value,java.util.List<T>> consumer, ObjectParser.NamedObjectParser<T,Context> namedObjectParser, java.util.function.Consumer<Value> orderedModeCallback, ParseField parseField)
Description copied from class:AbstractObjectParser
Declares named objects in the style of highlighting's field element. These are usually named inside and object like this:{ "highlight": { "fields": { <------ this one "title": {}, "body": {}, "category": {} } } }
{ "highlight": { "fields": [ <------ this one {"title": {}}, {"body": {}}, {"category": {}} ] } }
- Specified by:
declareNamedObjects
in classAbstractObjectParser<Value,Context>
- Parameters:
consumer
- sets the values once they have been parsednamedObjectParser
- parses each named objectorderedModeCallback
- called when the named object is parsed using the "ordered" mode (the array of objects)parseField
- the field to parse
-
getName
public java.lang.String getName()
- Specified by:
getName
in classAbstractObjectParser<Value,Context>
-
-