Răsfoiți Sursa

Add expected mapping type to `MapperException` (#31564)

Currently if a document cannot be indexed because it violates the defined 
mapping for the index, a MapperException is thrown. In some cases it is 
useful to expose the expected field type in the exception itself, 
so that the user can react based on the error message. This change adds 
the expected data type to the MapperException.

Closes #31502
lipsill 7 ani în urmă
părinte
comite
be54ba39c4

+ 2 - 1
server/src/main/java/org/elasticsearch/index/mapper/FieldMapper.java

@@ -276,7 +276,8 @@ public abstract class FieldMapper extends Mapper implements Cloneable {
                 context.doc().add(field);
             }
         } catch (Exception e) {
-            throw new MapperParsingException("failed to parse [" + fieldType().name() + "]", e);
+            throw new MapperParsingException("failed to parse field [{}] of type [{}]", e, fieldType().name(),
+                    fieldType().typeName());
         }
         multiFields.parse(this, context);
         return null;

+ 2 - 1
server/src/main/java/org/elasticsearch/index/mapper/GeoShapeFieldMapper.java

@@ -510,7 +510,8 @@ public class GeoShapeFieldMapper extends FieldMapper {
             indexShape(context, shape);
         } catch (Exception e) {
             if (ignoreMalformed.value() == false) {
-                throw new MapperParsingException("failed to parse [" + fieldType().name() + "]", e);
+                throw new MapperParsingException("failed to parse field [{}] of type [{}]", e, fieldType().name(),
+                        fieldType().typeName());
             }
             context.addIgnoredField(fieldType.name());
         }

+ 1 - 1
server/src/test/java/org/elasticsearch/index/mapper/BooleanFieldMapperTests.java

@@ -142,7 +142,7 @@ public class BooleanFieldMapperTests extends ESSingleNodeTestCase {
                 .endObject());
         MapperParsingException ex = expectThrows(MapperParsingException.class,
                 () -> defaultMapper.parse(SourceToParse.source("test", "type", "1", source, XContentType.JSON)));
-        assertEquals("failed to parse [field]", ex.getMessage());
+        assertEquals("failed to parse field [field] of type [boolean]", ex.getMessage());
     }
 
     public void testMultiFields() throws IOException {

+ 29 - 0
server/src/test/java/org/elasticsearch/index/mapper/DocumentParserTests.java

@@ -125,6 +125,35 @@ public class DocumentParserTests extends ESSingleNodeTestCase {
                 e.getMessage());
     }
 
+    public void testUnexpectedFieldMappingType() throws Exception {
+        DocumentMapperParser mapperParser = createIndex("test").mapperService().documentMapperParser();
+        String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type").startObject("properties")
+                .startObject("foo").field("type", "long").endObject()
+                .startObject("bar").field("type", "boolean").endObject()
+                .startObject("geo").field("type", "geo_shape").endObject()
+                .endObject().endObject().endObject());
+        DocumentMapper mapper = mapperParser.parse("type", new CompressedXContent(mapping));
+        {
+            BytesReference bytes = BytesReference.bytes(XContentFactory.jsonBuilder().startObject().field("foo", true).endObject());
+            MapperException exception = expectThrows(MapperException.class,
+                    () -> mapper.parse(SourceToParse.source("test", "type", "1", bytes, XContentType.JSON)));
+            assertThat(exception.getMessage(), containsString("failed to parse field [foo] of type [long]"));
+        }
+        {
+            BytesReference bytes = BytesReference.bytes(XContentFactory.jsonBuilder().startObject().field("bar", "bar").endObject());
+            MapperException exception = expectThrows(MapperException.class,
+                    () -> mapper.parse(SourceToParse.source("test", "type", "2", bytes, XContentType.JSON)));
+            assertThat(exception.getMessage(), containsString("failed to parse field [bar] of type [boolean]"));
+        }
+        {
+            BytesReference bytes = BytesReference.bytes(XContentFactory.jsonBuilder().startObject().field("geo", 123).endObject());
+            MapperException exception = expectThrows(MapperException.class,
+                    () -> mapper.parse(SourceToParse.source("test", "type", "2", bytes, XContentType.JSON)));
+            assertThat(exception.getMessage(), containsString("failed to parse field [geo] of type [geo_shape]"));
+        }
+
+    }
+
     public void testDotsWithDynamicNestedMapper() throws Exception {
         DocumentMapperParser mapperParser = createIndex("test").mapperService().documentMapperParser();
         String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")