Skip to content

Commit c31a5b1

Browse files
author
Christoph Büscher
authored
Fix error applying ignore_malformed to boolean values (#41261)
The `ignore_malformed` option currently works on numeric fields only when the bad value isn't a string value but not if it is a boolean. In this case we get a parsing error from the xContent parser which we need to catch in addition to the field mapper. Closes #11498
1 parent f3ac4e6 commit c31a5b1

File tree

2 files changed

+59
-33
lines changed

2 files changed

+59
-33
lines changed

server/src/main/java/org/elasticsearch/index/mapper/NumberFieldMapper.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

2020
package org.elasticsearch.index.mapper;
2121

22+
import com.fasterxml.jackson.core.JsonParseException;
23+
2224
import org.apache.lucene.document.DoublePoint;
2325
import org.apache.lucene.document.Field;
2426
import org.apache.lucene.document.FloatPoint;
@@ -1042,8 +1044,8 @@ protected void parseCreateField(ParseContext context, List<IndexableField> field
10421044
} else {
10431045
try {
10441046
numericValue = fieldType().type.parse(parser, coerce.value());
1045-
} catch (IllegalArgumentException e) {
1046-
if (ignoreMalformed.value()) {
1047+
} catch (IllegalArgumentException | JsonParseException e) {
1048+
if (ignoreMalformed.value() && parser.currentToken().isValue()) {
10471049
context.addIgnoredField(fieldType.name());
10481050
return;
10491051
} else {

server/src/test/java/org/elasticsearch/index/mapper/NumberFieldMapperTests.java

Lines changed: 55 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,14 @@
2020
package org.elasticsearch.index.mapper;
2121

2222
import com.carrotsearch.randomizedtesting.annotations.Timeout;
23+
2324
import org.apache.lucene.index.DocValuesType;
2425
import org.apache.lucene.index.IndexableField;
2526
import org.elasticsearch.common.Strings;
2627
import org.elasticsearch.common.bytes.BytesReference;
2728
import org.elasticsearch.common.compress.CompressedXContent;
29+
import org.elasticsearch.common.xcontent.ToXContentObject;
30+
import org.elasticsearch.common.xcontent.XContentBuilder;
2831
import org.elasticsearch.common.xcontent.XContentFactory;
2932
import org.elasticsearch.common.xcontent.XContentType;
3033
import org.elasticsearch.index.mapper.NumberFieldMapper.NumberType;
@@ -37,6 +40,7 @@
3740
import java.util.HashSet;
3841
import java.util.List;
3942

43+
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
4044
import static org.hamcrest.Matchers.containsString;
4145

4246
public class NumberFieldMapperTests extends AbstractNumericFieldMapperTestCase {
@@ -218,45 +222,65 @@ protected void doTestDecimalCoerce(String type) throws IOException {
218222

219223
public void testIgnoreMalformed() throws Exception {
220224
for (String type : TYPES) {
221-
doTestIgnoreMalformed(type);
222-
}
223-
}
225+
for (Object malformedValue : new Object[] { "a", Boolean.FALSE }) {
226+
String mapping = Strings.toString(jsonBuilder().startObject().startObject("type").startObject("properties")
227+
.startObject("field").field("type", type).endObject().endObject().endObject().endObject());
224228

225-
private void doTestIgnoreMalformed(String type) throws IOException {
226-
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
227-
.startObject("properties").startObject("field").field("type", type).endObject().endObject()
228-
.endObject().endObject());
229+
DocumentMapper mapper = parser.parse("type", new CompressedXContent(mapping));
229230

230-
DocumentMapper mapper = parser.parse("type", new CompressedXContent(mapping));
231+
assertEquals(mapping, mapper.mappingSource().toString());
231232

232-
assertEquals(mapping, mapper.mappingSource().toString());
233+
ThrowingRunnable runnable = () -> mapper.parse(new SourceToParse("test", "type", "1",
234+
BytesReference.bytes(jsonBuilder().startObject().field("field", malformedValue).endObject()), XContentType.JSON));
235+
MapperParsingException e = expectThrows(MapperParsingException.class, runnable);
236+
if (malformedValue instanceof String) {
237+
assertThat(e.getCause().getMessage(), containsString("For input string: \"a\""));
238+
} else {
239+
assertThat(e.getCause().getMessage(), containsString("Current token"));
240+
assertThat(e.getCause().getMessage(), containsString("not numeric, can not use numeric value accessors"));
241+
}
233242

234-
ThrowingRunnable runnable = () -> mapper.parse(new SourceToParse("test", "type", "1", BytesReference
235-
.bytes(XContentFactory.jsonBuilder()
236-
.startObject()
237-
.field("field", "a")
238-
.endObject()),
239-
XContentType.JSON));
240-
MapperParsingException e = expectThrows(MapperParsingException.class, runnable);
241-
242-
assertThat(e.getCause().getMessage(), containsString("For input string: \"a\""));
243+
mapping = Strings.toString(jsonBuilder().startObject().startObject("type").startObject("properties").startObject("field")
244+
.field("type", type).field("ignore_malformed", true).endObject().endObject().endObject().endObject());
243245

244-
mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")
245-
.startObject("properties").startObject("field").field("type", type).field("ignore_malformed", true).endObject().endObject()
246-
.endObject().endObject());
246+
DocumentMapper mapper2 = parser.parse("type", new CompressedXContent(mapping));
247247

248-
DocumentMapper mapper2 = parser.parse("type", new CompressedXContent(mapping));
248+
ParsedDocument doc = mapper2.parse(new SourceToParse("test", "type", "1",
249+
BytesReference.bytes(jsonBuilder().startObject().field("field", malformedValue).endObject()), XContentType.JSON));
249250

250-
ParsedDocument doc = mapper2.parse(new SourceToParse("test", "type", "1", BytesReference
251-
.bytes(XContentFactory.jsonBuilder()
252-
.startObject()
253-
.field("field", "a")
254-
.endObject()),
255-
XContentType.JSON));
251+
IndexableField[] fields = doc.rootDoc().getFields("field");
252+
assertEquals(0, fields.length);
253+
assertArrayEquals(new String[] { "field" }, doc.rootDoc().getValues("_ignored"));
254+
}
255+
}
256+
}
256257

257-
IndexableField[] fields = doc.rootDoc().getFields("field");
258-
assertEquals(0, fields.length);
259-
assertArrayEquals(new String[] { "field" }, doc.rootDoc().getValues("_ignored"));
258+
/**
259+
* Test that in case the malformed value is an xContent object we throw error regardless of `ignore_malformed`
260+
*/
261+
public void testIgnoreMalformedWithObject() throws Exception {
262+
for (String type : TYPES) {
263+
Object malformedValue = new ToXContentObject() {
264+
@Override
265+
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
266+
return builder.startObject().field("foo", "bar").endObject();
267+
}
268+
};
269+
for (Boolean ignoreMalformed : new Boolean[] { true, false }) {
270+
String mapping = Strings.toString(
271+
jsonBuilder().startObject().startObject("type").startObject("properties").startObject("field").field("type", type)
272+
.field("ignore_malformed", ignoreMalformed).endObject().endObject().endObject().endObject());
273+
DocumentMapper mapper = parser.parse("type", new CompressedXContent(mapping));
274+
assertEquals(mapping, mapper.mappingSource().toString());
275+
276+
MapperParsingException e = expectThrows(MapperParsingException.class,
277+
() -> mapper.parse(new SourceToParse("test", "type", "1",
278+
BytesReference.bytes(jsonBuilder().startObject().field("field", malformedValue).endObject()),
279+
XContentType.JSON)));
280+
assertThat(e.getCause().getMessage(), containsString("Current token"));
281+
assertThat(e.getCause().getMessage(), containsString("not numeric, can not use numeric value accessors"));
282+
}
283+
}
260284
}
261285

262286
public void testRejectNorms() throws IOException {

0 commit comments

Comments
 (0)