Added parsing of erroneous field value (#42321)
This commit is contained in:
parent
6e7a0e1b2a
commit
cf610b5e81
|
@ -289,7 +289,7 @@ public abstract class AbstractXContentParser implements XContentParser {
|
|||
return readListOrderedMap(this);
|
||||
}
|
||||
|
||||
interface MapFactory {
|
||||
public interface MapFactory {
|
||||
Map<String, Object> newMap();
|
||||
}
|
||||
|
||||
|
@ -391,7 +391,7 @@ public abstract class AbstractXContentParser implements XContentParser {
|
|||
return list;
|
||||
}
|
||||
|
||||
static Object readValue(XContentParser parser, MapFactory mapFactory, XContentParser.Token token) throws IOException {
|
||||
public static Object readValue(XContentParser parser, MapFactory mapFactory, XContentParser.Token token) throws IOException {
|
||||
if (token == XContentParser.Token.VALUE_NULL) {
|
||||
return null;
|
||||
} else if (token == XContentParser.Token.VALUE_STRING) {
|
||||
|
|
|
@ -33,6 +33,8 @@ import org.elasticsearch.common.settings.Setting;
|
|||
import org.elasticsearch.common.settings.Setting.Property;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.common.xcontent.support.AbstractXContentParser;
|
||||
import org.elasticsearch.index.analysis.NamedAnalyzer;
|
||||
import org.elasticsearch.index.mapper.FieldNamesFieldMapper.FieldNamesFieldType;
|
||||
import org.elasticsearch.index.similarity.SimilarityProvider;
|
||||
|
@ -46,6 +48,7 @@ import java.util.Comparator;
|
|||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
|
@ -276,14 +279,33 @@ public abstract class FieldMapper extends Mapper implements Cloneable {
|
|||
context.doc().add(field);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new MapperParsingException("failed to parse field [{}] of type [{}] in document with id '{}'", e, fieldType().name(),
|
||||
fieldType().typeName(), context.sourceToParse().id());
|
||||
String valuePreview = "";
|
||||
try {
|
||||
XContentParser parser = context.parser();
|
||||
Object complexValue = AbstractXContentParser.readValue(parser, HashMap::new, parser.currentToken());
|
||||
if (complexValue == null) {
|
||||
valuePreview = "null";
|
||||
} else {
|
||||
valuePreview = complexValue.toString();
|
||||
}
|
||||
} catch (Exception innerException) {
|
||||
throw new MapperParsingException("failed to parse field [{}] of type [{}] in document with id '{}'. " +
|
||||
"Could not parse field value preview,",
|
||||
e, fieldType().name(), fieldType().typeName(), context.sourceToParse().id());
|
||||
}
|
||||
|
||||
throw new MapperParsingException("failed to parse field [{}] of type [{}] in document with id '{}'. " +
|
||||
"Preview of field's value: '{}'", e, fieldType().name(), fieldType().typeName(),
|
||||
context.sourceToParse().id(), valuePreview);
|
||||
}
|
||||
multiFields.parse(this, context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the field value and populate <code>fields</code>.
|
||||
*
|
||||
* Implementations of this method should ensure that on failing to parse parser.currentToken() must be the
|
||||
* current failing token
|
||||
*/
|
||||
protected abstract void parseCreateField(ParseContext context, List<IndexableField> fields) throws IOException;
|
||||
|
||||
|
|
|
@ -135,16 +135,48 @@ public class BooleanFieldMapperTests extends ESSingleNodeTestCase {
|
|||
.endObject()
|
||||
.endObject());
|
||||
DocumentMapper defaultMapper = parser.parse("type", new CompressedXContent(mapping));
|
||||
// omit "false"/"true" here as they should still be parsed correctly
|
||||
String randomValue = randomFrom("off", "no", "0", "on", "yes", "1");
|
||||
BytesReference source = BytesReference.bytes(XContentFactory.jsonBuilder()
|
||||
.startObject()
|
||||
// omit "false"/"true" here as they should still be parsed correctly
|
||||
.field("field", randomFrom("off", "no", "0", "on", "yes", "1"))
|
||||
.field("field", randomValue)
|
||||
.endObject());
|
||||
MapperParsingException ex = expectThrows(MapperParsingException.class,
|
||||
() -> defaultMapper.parse(new SourceToParse("test", "type", "1", source, XContentType.JSON)));
|
||||
assertEquals("failed to parse field [field] of type [boolean] in document with id '1'", ex.getMessage());
|
||||
assertEquals("failed to parse field [field] of type [boolean] in document with id '1'. " +
|
||||
"Preview of field's value: '" + randomValue + "'", ex.getMessage());
|
||||
}
|
||||
|
||||
|
||||
public void testParsesBooleansNestedStrict() throws IOException {
|
||||
String mapping = Strings.toString(XContentFactory.jsonBuilder()
|
||||
.startObject()
|
||||
.startObject("type")
|
||||
.startObject("properties")
|
||||
.startObject("field")
|
||||
.field("type", "boolean")
|
||||
.endObject()
|
||||
.endObject()
|
||||
.endObject()
|
||||
.endObject());
|
||||
DocumentMapper defaultMapper = parser.parse("type", new CompressedXContent(mapping));
|
||||
// omit "false"/"true" here as they should still be parsed correctly
|
||||
String randomValue = "no";
|
||||
BytesReference source = BytesReference.bytes(XContentFactory.jsonBuilder()
|
||||
.startObject()
|
||||
.startObject("field")
|
||||
.field("inner_field", randomValue)
|
||||
.endObject()
|
||||
.endObject());
|
||||
MapperParsingException ex = expectThrows(MapperParsingException.class,
|
||||
() -> defaultMapper.parse(new SourceToParse("test", "type", "1", source, XContentType.JSON)));
|
||||
assertEquals("failed to parse field [field] of type [boolean] in document with id '1'. " +
|
||||
"Preview of field's value: '{inner_field=" + randomValue + "}'", ex.getMessage());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public void testMultiFields() throws IOException {
|
||||
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
|
||||
.startObject("properties")
|
||||
|
|
|
@ -386,6 +386,85 @@ public class KeywordFieldMapperTests extends ESSingleNodeTestCase {
|
|||
assertEquals(DocValuesType.SORTED_SET, fieldType.docValuesType());
|
||||
}
|
||||
|
||||
public void testParsesKeywordNestedEmptyObjectStrict() throws IOException {
|
||||
String mapping = Strings.toString(XContentFactory.jsonBuilder()
|
||||
.startObject()
|
||||
.startObject("type")
|
||||
.startObject("properties")
|
||||
.startObject("field")
|
||||
.field("type", "keyword")
|
||||
.endObject()
|
||||
.endObject()
|
||||
.endObject()
|
||||
.endObject());
|
||||
DocumentMapper defaultMapper = parser.parse("type", new CompressedXContent(mapping));
|
||||
|
||||
BytesReference source = BytesReference.bytes(XContentFactory.jsonBuilder()
|
||||
.startObject()
|
||||
.startObject("field")
|
||||
.endObject()
|
||||
.endObject());
|
||||
MapperParsingException ex = expectThrows(MapperParsingException.class,
|
||||
() -> defaultMapper.parse(new SourceToParse("test", "type", "1", source, XContentType.JSON)));
|
||||
assertEquals("failed to parse field [field] of type [keyword] in document with id '1'. " +
|
||||
"Preview of field's value: '{}'", ex.getMessage());
|
||||
}
|
||||
|
||||
public void testParsesKeywordNestedListStrict() throws IOException {
|
||||
String mapping = Strings.toString(XContentFactory.jsonBuilder()
|
||||
.startObject()
|
||||
.startObject("type")
|
||||
.startObject("properties")
|
||||
.startObject("field")
|
||||
.field("type", "keyword")
|
||||
.endObject()
|
||||
.endObject()
|
||||
.endObject()
|
||||
.endObject());
|
||||
DocumentMapper defaultMapper = parser.parse("type", new CompressedXContent(mapping));
|
||||
|
||||
BytesReference source = BytesReference.bytes(XContentFactory.jsonBuilder()
|
||||
.startObject()
|
||||
.startArray("field")
|
||||
.startObject()
|
||||
.startArray("array_name")
|
||||
.value("inner_field_first")
|
||||
.value("inner_field_second")
|
||||
.endArray()
|
||||
.endObject()
|
||||
.endArray()
|
||||
.endObject());
|
||||
MapperParsingException ex = expectThrows(MapperParsingException.class,
|
||||
() -> defaultMapper.parse(new SourceToParse("test", "type", "1", source, XContentType.JSON)));
|
||||
assertEquals("failed to parse field [field] of type [keyword] in document with id '1'. " +
|
||||
"Preview of field's value: '{array_name=[inner_field_first, inner_field_second]}'", ex.getMessage());
|
||||
}
|
||||
|
||||
public void testParsesKeywordNullStrict() throws IOException {
|
||||
String mapping = Strings.toString(XContentFactory.jsonBuilder()
|
||||
.startObject()
|
||||
.startObject("type")
|
||||
.startObject("properties")
|
||||
.startObject("field")
|
||||
.field("type", "keyword")
|
||||
.endObject()
|
||||
.endObject()
|
||||
.endObject()
|
||||
.endObject());
|
||||
DocumentMapper defaultMapper = parser.parse("type", new CompressedXContent(mapping));
|
||||
|
||||
BytesReference source = BytesReference.bytes(XContentFactory.jsonBuilder()
|
||||
.startObject()
|
||||
.startObject("field")
|
||||
.nullField("field_name")
|
||||
.endObject()
|
||||
.endObject());
|
||||
MapperParsingException ex = expectThrows(MapperParsingException.class,
|
||||
() -> defaultMapper.parse(new SourceToParse("test", "type", "1", source, XContentType.JSON)));
|
||||
assertEquals("failed to parse field [field] of type [keyword] in document with id '1'. " +
|
||||
"Preview of field's value: '{field_name=null}'", ex.getMessage());
|
||||
}
|
||||
|
||||
public void testUpdateNormalizer() throws IOException {
|
||||
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
|
||||
.startObject("properties").startObject("field")
|
||||
|
|
Loading…
Reference in New Issue