Skip to content

Commit

Permalink
Move ObjectParser into the x-content lib (#29373)
Browse files Browse the repository at this point in the history
* Move ObjectParser into the x-content lib

This moves `ObjectParser`, `AbstractObjectParser`, and
`ConstructingObjectParser` into the libs/x-content dependency. This decoupling
allows them to be used for parsing for projects that don't want to depend on the
entire Elasticsearch jar.

Relates to #28504
  • Loading branch information
dakrone committed Apr 6, 2018
1 parent 7de5814 commit 37eb2b1
Show file tree
Hide file tree
Showing 31 changed files with 308 additions and 213 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,8 @@

import org.elasticsearch.common.CheckedFunction;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.xcontent.ObjectParser.NamedObjectParser;
import org.elasticsearch.common.xcontent.ObjectParser.ValueType;
import org.elasticsearch.common.xcontent.json.JsonXContent;

import java.io.IOException;
import java.util.ArrayList;
Expand Down Expand Up @@ -214,17 +212,6 @@ public <T> void declareFieldArray(BiConsumer<Value, List<T>> consumer, ContextPa
declareField(consumer, (p, c) -> parseArray(p, () -> itemParser.parse(p, c)), field, type);
}

public void declareRawObject(BiConsumer<Value, BytesReference> consumer, ParseField field) {
CheckedFunction<XContentParser, BytesReference, IOException> bytesParser = p -> {
try (XContentBuilder builder = JsonXContent.contentBuilder()) {
builder.prettyPrint();
builder.copyCurrentStructure(p);
return BytesReference.bytes(builder);
}
};
declareField(consumer, bytesParser, field, ValueType.OBJECT);
}

private interface IOSupplier<T> {
T get() throws IOException;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
package org.elasticsearch.common.xcontent;

import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.ParsingException;
import org.elasticsearch.common.xcontent.ObjectParser.NamedObjectParser;
import org.elasticsearch.common.xcontent.ObjectParser.ValueType;

Expand Down Expand Up @@ -161,7 +160,7 @@ public Value apply(XContentParser parser, Context context) {
try {
return parse(parser, context);
} catch (IOException e) {
throw new ParsingException(parser.getTokenLocation(), "[" + objectParser.getName() + "] failed to parse object", e);
throw new XContentParseException(parser.getTokenLocation(), "[" + objectParser.getName() + "] failed to parse object", e);
}
}

Expand Down Expand Up @@ -335,7 +334,7 @@ private <T> BiConsumer<Target, T> queueingConsumer(BiConsumer<Value, T> consumer
try {
consumer.accept(targetObject, v);
} catch (Exception e) {
throw new ParsingException(location,
throw new XContentParseException(location,
"[" + objectParser.getName() + "] failed to parse field [" + parseField.getPreferredName() + "]", e);
}
});
Expand Down Expand Up @@ -413,7 +412,7 @@ private void constructorArg(int position, ParseField parseField, Object value) {
private void queue(Consumer<Value> queueMe) {
assert targetObject == null: "Don't queue after the targetObject has been built! Just apply the consumer directly.";
if (queuedFields == null) {
@SuppressWarnings("unchecked")
@SuppressWarnings({"unchecked", "rawtypes"})
Consumer<Value>[] queuedFields = new Consumer[numberOfFields];
this.queuedFields = queuedFields;
}
Expand Down Expand Up @@ -471,11 +470,12 @@ private void buildTarget() {
queuedFieldsCount -= 1;
queuedFields[queuedFieldsCount].accept(targetObject);
}
} catch (ParsingException e) {
throw new ParsingException(e.getLineNumber(), e.getColumnNumber(),
"failed to build [" + objectParser.getName() + "] after last required field arrived", e);
} catch (XContentParseException e) {
throw new XContentParseException(e.getLocation(),
"failed to build [" + objectParser.getName() + "] after last required field arrived", e);
} catch (Exception e) {
throw new ParsingException(null, "Failed to build [" + objectParser.getName() + "] after last required field arrived", e);
throw new XContentParseException(null,
"Failed to build [" + objectParser.getName() + "] after last required field arrived", e);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@

import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.ParsingException;

import java.io.IOException;
import java.lang.reflect.Array;
Expand Down Expand Up @@ -147,7 +146,7 @@ public Value parse(XContentParser parser, Value value, Context context) throws I
} else {
token = parser.nextToken();
if (token != XContentParser.Token.START_OBJECT) {
throw new ParsingException(parser.getTokenLocation(), "[" + name + "] Expected START_OBJECT but was: " + token);
throw new XContentParseException(parser.getTokenLocation(), "[" + name + "] Expected START_OBJECT but was: " + token);
}
}

Expand All @@ -159,7 +158,7 @@ public Value parse(XContentParser parser, Value value, Context context) throws I
fieldParser = getParser(currentFieldName);
} else {
if (currentFieldName == null) {
throw new ParsingException(parser.getTokenLocation(), "[" + name + "] no field found");
throw new XContentParseException(parser.getTokenLocation(), "[" + name + "] no field found");
}
if (fieldParser == null) {
assert ignoreUnknownFields : "this should only be possible if configured to ignore known fields";
Expand All @@ -182,7 +181,7 @@ public Value apply(XContentParser parser, Context context) {
try {
return parse(parser, valueSupplier.get(), context);
} catch (IOException e) {
throw new ParsingException(parser.getTokenLocation(), "[" + name + "] failed to parse object", e);
throw new XContentParseException(parser.getTokenLocation(), "[" + name + "] failed to parse object", e);
}
}

Expand Down Expand Up @@ -233,7 +232,7 @@ public <T> void declareNamedObjects(BiConsumer<Value, List<T>> consumer, NamedOb
// This creates and parses the named object
BiFunction<XContentParser, Context, T> objectParser = (XContentParser p, Context c) -> {
if (p.currentToken() != XContentParser.Token.FIELD_NAME) {
throw new ParsingException(p.getTokenLocation(), "[" + field + "] can be a single object with any number of "
throw new XContentParseException(p.getTokenLocation(), "[" + field + "] can be a single object with any number of "
+ "fields or an array where each entry is an object with a single field");
}
// This messy exception nesting has the nice side effect of telling the use which field failed to parse
Expand All @@ -242,10 +241,10 @@ public <T> void declareNamedObjects(BiConsumer<Value, List<T>> consumer, NamedOb
try {
return namedObjectParser.parse(p, c, name);
} catch (Exception e) {
throw new ParsingException(p.getTokenLocation(), "[" + field + "] failed to parse field [" + name + "]", e);
throw new XContentParseException(p.getTokenLocation(), "[" + field + "] failed to parse field [" + name + "]", e);
}
} catch (IOException e) {
throw new ParsingException(p.getTokenLocation(), "[" + field + "] error while parsing", e);
throw new XContentParseException(p.getTokenLocation(), "[" + field + "] error while parsing", e);
}
};
declareField((XContentParser p, Value v, Context c) -> {
Expand All @@ -261,14 +260,14 @@ public <T> void declareNamedObjects(BiConsumer<Value, List<T>> consumer, NamedOb
orderedModeCallback.accept(v);
while ((token = p.nextToken()) != XContentParser.Token.END_ARRAY) {
if (token != XContentParser.Token.START_OBJECT) {
throw new ParsingException(p.getTokenLocation(), "[" + field + "] can be a single object with any number of "
throw new XContentParseException(p.getTokenLocation(), "[" + field + "] can be a single object with any number of "
+ "fields or an array where each entry is an object with a single field");
}
p.nextToken(); // Move to the first field in the object
fields.add(objectParser.apply(p, c));
p.nextToken(); // Move past the object, should be back to into the array
if (p.currentToken() != XContentParser.Token.END_OBJECT) {
throw new ParsingException(p.getTokenLocation(), "[" + field + "] can be a single object with any number of "
throw new XContentParseException(p.getTokenLocation(), "[" + field + "] can be a single object with any number of "
+ "fields or an array where each entry is an object with a single field");
}
}
Expand Down Expand Up @@ -314,7 +313,8 @@ private void parseValue(XContentParser parser, FieldParser fieldParser, String c
try {
fieldParser.parser.parse(parser, value, context);
} catch (Exception ex) {
throw new ParsingException(parser.getTokenLocation(), "[" + name + "] failed to parse field [" + currentFieldName + "]", ex);
throw new XContentParseException(parser.getTokenLocation(),
"[" + name + "] failed to parse field [" + currentFieldName + "]", ex);
}
}

Expand All @@ -331,7 +331,7 @@ private void parseSub(XContentParser parser, FieldParser fieldParser, String cur
case END_OBJECT:
case END_ARRAY:
case FIELD_NAME:
throw new ParsingException(parser.getTokenLocation(), "[" + name + "]" + token + " is unexpected");
throw new XContentParseException(parser.getTokenLocation(), "[" + name + "]" + token + " is unexpected");
case VALUE_STRING:
case VALUE_NUMBER:
case VALUE_BOOLEAN:
Expand Down Expand Up @@ -364,11 +364,11 @@ private class FieldParser {

void assertSupports(String parserName, XContentParser parser, String currentFieldName) {
if (parseField.match(currentFieldName, parser.getDeprecationHandler()) == false) {
throw new ParsingException(parser.getTokenLocation(),
throw new XContentParseException(parser.getTokenLocation(),
"[" + parserName + "] parsefield doesn't accept: " + currentFieldName);
}
if (supportedTokens.contains(parser.currentToken()) == false) {
throw new ParsingException(parser.getTokenLocation(),
throw new XContentParseException(parser.getTokenLocation(),
"[" + parserName + "] " + currentFieldName + " doesn't support values of type: " + parser.currentToken());
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

package org.elasticsearch.common.xcontent;

import org.elasticsearch.common.Nullable;

import java.util.Optional;

/**
Expand All @@ -37,6 +39,11 @@ public XContentParseException(XContentLocation location, String message) {
this.location = Optional.ofNullable(location);
}

public XContentParseException(XContentLocation location, String message, Exception cause) {
super(message, cause);
this.location = Optional.ofNullable(location);
}

public int getLineNumber() {
return location.map(l -> l.lineNumber).orElse(-1);
}
Expand All @@ -45,8 +52,14 @@ public int getColumnNumber() {
return location.map(l -> l.columnNumber).orElse(-1);
}

@Nullable
public XContentLocation getLocation() {
return location.orElse(null);
}

@Override
public String getMessage() {
return location.map(l -> "[" + l.toString() + "] ").orElse("") + super.getMessage();
}

}
Loading

0 comments on commit 37eb2b1

Please sign in to comment.