Mappings: Fix dynamic check to properly handle parents
This change fixes the lookup during document parsing of whether an object field is dynamic to handle looking up through parent object mappers, and also handle when a parent object mapper was created during document parsing. closes #17854
This commit is contained in:
parent
b8899cdb78
commit
d68318fb6c
|
@ -480,7 +480,7 @@ final class DocumentParser {
|
||||||
if (objectMapper != null) {
|
if (objectMapper != null) {
|
||||||
parseObjectOrField(context, objectMapper);
|
parseObjectOrField(context, objectMapper);
|
||||||
} else {
|
} else {
|
||||||
ObjectMapper.Dynamic dynamic = dynamicOrDefault(mapper, context.root().dynamic());
|
ObjectMapper.Dynamic dynamic = dynamicOrDefault(mapper, context);
|
||||||
if (dynamic == ObjectMapper.Dynamic.STRICT) {
|
if (dynamic == ObjectMapper.Dynamic.STRICT) {
|
||||||
throw new StrictDynamicMappingException(mapper.fullPath(), currentFieldName);
|
throw new StrictDynamicMappingException(mapper.fullPath(), currentFieldName);
|
||||||
} else if (dynamic == ObjectMapper.Dynamic.TRUE) {
|
} else if (dynamic == ObjectMapper.Dynamic.TRUE) {
|
||||||
|
@ -519,7 +519,7 @@ final class DocumentParser {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
ObjectMapper.Dynamic dynamic = dynamicOrDefault(parentMapper, context.root().dynamic());
|
ObjectMapper.Dynamic dynamic = dynamicOrDefault(parentMapper, context);
|
||||||
if (dynamic == ObjectMapper.Dynamic.STRICT) {
|
if (dynamic == ObjectMapper.Dynamic.STRICT) {
|
||||||
throw new StrictDynamicMappingException(parentMapper.fullPath(), arrayFieldName);
|
throw new StrictDynamicMappingException(parentMapper.fullPath(), arrayFieldName);
|
||||||
} else if (dynamic == ObjectMapper.Dynamic.TRUE) {
|
} else if (dynamic == ObjectMapper.Dynamic.TRUE) {
|
||||||
|
@ -794,7 +794,7 @@ final class DocumentParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void parseDynamicValue(final ParseContext context, ObjectMapper parentMapper, String currentFieldName, XContentParser.Token token) throws IOException {
|
private static void parseDynamicValue(final ParseContext context, ObjectMapper parentMapper, String currentFieldName, XContentParser.Token token) throws IOException {
|
||||||
ObjectMapper.Dynamic dynamic = dynamicOrDefault(parentMapper, context.root().dynamic());
|
ObjectMapper.Dynamic dynamic = dynamicOrDefault(parentMapper, context);
|
||||||
if (dynamic == ObjectMapper.Dynamic.STRICT) {
|
if (dynamic == ObjectMapper.Dynamic.STRICT) {
|
||||||
throw new StrictDynamicMappingException(parentMapper.fullPath(), currentFieldName);
|
throw new StrictDynamicMappingException(parentMapper.fullPath(), currentFieldName);
|
||||||
}
|
}
|
||||||
|
@ -867,7 +867,7 @@ final class DocumentParser {
|
||||||
mapper = context.docMapper().objectMappers().get(context.path().pathAsText(paths[i]));
|
mapper = context.docMapper().objectMappers().get(context.path().pathAsText(paths[i]));
|
||||||
if (mapper == null) {
|
if (mapper == null) {
|
||||||
// One mapping is missing, check if we are allowed to create a dynamic one.
|
// One mapping is missing, check if we are allowed to create a dynamic one.
|
||||||
ObjectMapper.Dynamic dynamic = dynamicOrDefault(parent, context.root().dynamic());
|
ObjectMapper.Dynamic dynamic = dynamicOrDefault(parent, context);
|
||||||
|
|
||||||
switch (dynamic) {
|
switch (dynamic) {
|
||||||
case STRICT:
|
case STRICT:
|
||||||
|
@ -899,10 +899,26 @@ final class DocumentParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ObjectMapper.Dynamic dynamicOrDefault(ObjectMapper parentMapper, ObjectMapper.Dynamic dynamicDefault) {
|
// find what the dynamic setting is given the current parse context and parent
|
||||||
|
private static ObjectMapper.Dynamic dynamicOrDefault(ObjectMapper parentMapper, ParseContext context) {
|
||||||
ObjectMapper.Dynamic dynamic = parentMapper.dynamic();
|
ObjectMapper.Dynamic dynamic = parentMapper.dynamic();
|
||||||
|
while (dynamic == null) {
|
||||||
|
int lastDotNdx = parentMapper.name().lastIndexOf('.');
|
||||||
|
if (lastDotNdx == -1) {
|
||||||
|
// no dot means we the parent is the root, so just delegate to the default outside the loop
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
String parentName = parentMapper.name().substring(0, lastDotNdx);
|
||||||
|
parentMapper = context.docMapper().objectMappers().get(parentName);
|
||||||
|
if (parentMapper == null) {
|
||||||
|
// If parentMapper is ever null, it means the parent of the current mapper was dynamically created.
|
||||||
|
// But in order to be created dynamically, the dynamic setting of that parent was necessarily true
|
||||||
|
return ObjectMapper.Dynamic.TRUE;
|
||||||
|
}
|
||||||
|
dynamic = parentMapper.dynamic();
|
||||||
|
}
|
||||||
if (dynamic == null) {
|
if (dynamic == null) {
|
||||||
return dynamicDefault == null ? ObjectMapper.Dynamic.TRUE : dynamicDefault;
|
return context.root().dynamic() == null ? ObjectMapper.Dynamic.TRUE : context.root().dynamic();
|
||||||
}
|
}
|
||||||
return dynamic;
|
return dynamic;
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,6 +98,65 @@ public class DocumentParserTests extends ESSingleNodeTestCase {
|
||||||
assertEquals("789", values[2]);
|
assertEquals("789", values[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testPropagateDynamicWithExistingMapper() throws Exception {
|
||||||
|
DocumentMapperParser mapperParser = createIndex("test").mapperService().documentMapperParser();
|
||||||
|
String mapping = XContentFactory.jsonBuilder().startObject().startObject("type")
|
||||||
|
.field("dynamic", false)
|
||||||
|
.startObject("properties")
|
||||||
|
.startObject("foo")
|
||||||
|
.field("type", "object")
|
||||||
|
.field("dynamic", true)
|
||||||
|
.startObject("properties")
|
||||||
|
.endObject().endObject().endObject().endObject().string();
|
||||||
|
DocumentMapper mapper = mapperParser.parse("type", new CompressedXContent(mapping));
|
||||||
|
BytesReference bytes = XContentFactory.jsonBuilder()
|
||||||
|
.startObject().startObject("foo")
|
||||||
|
.field("bar", "something")
|
||||||
|
.endObject().endObject().bytes();
|
||||||
|
ParsedDocument doc = mapper.parse("test", "type", "1", bytes);
|
||||||
|
assertNotNull(doc.dynamicMappingsUpdate());
|
||||||
|
assertNotNull(doc.rootDoc().getField("foo.bar"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testPropagateDynamicWithDynamicMapper() throws Exception {
|
||||||
|
DocumentMapperParser mapperParser = createIndex("test").mapperService().documentMapperParser();
|
||||||
|
String mapping = XContentFactory.jsonBuilder().startObject().startObject("type")
|
||||||
|
.field("dynamic", false)
|
||||||
|
.startObject("properties")
|
||||||
|
.startObject("foo")
|
||||||
|
.field("type", "object")
|
||||||
|
.field("dynamic", true)
|
||||||
|
.startObject("properties")
|
||||||
|
.endObject().endObject().endObject().endObject().string();
|
||||||
|
DocumentMapper mapper = mapperParser.parse("type", new CompressedXContent(mapping));
|
||||||
|
BytesReference bytes = XContentFactory.jsonBuilder()
|
||||||
|
.startObject().startObject("foo").startObject("bar")
|
||||||
|
.field("baz", "something")
|
||||||
|
.endObject().endObject().endObject().bytes();
|
||||||
|
ParsedDocument doc = mapper.parse("test", "type", "1", bytes);
|
||||||
|
assertNotNull(doc.dynamicMappingsUpdate());
|
||||||
|
assertNotNull(doc.rootDoc().getField("foo.bar.baz"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testDynamicRootFallback() throws Exception {
|
||||||
|
DocumentMapperParser mapperParser = createIndex("test").mapperService().documentMapperParser();
|
||||||
|
String mapping = XContentFactory.jsonBuilder().startObject().startObject("type")
|
||||||
|
.field("dynamic", false)
|
||||||
|
.startObject("properties")
|
||||||
|
.startObject("foo")
|
||||||
|
.field("type", "object")
|
||||||
|
.startObject("properties")
|
||||||
|
.endObject().endObject().endObject().endObject().string();
|
||||||
|
DocumentMapper mapper = mapperParser.parse("type", new CompressedXContent(mapping));
|
||||||
|
BytesReference bytes = XContentFactory.jsonBuilder()
|
||||||
|
.startObject().startObject("foo")
|
||||||
|
.field("bar", "something")
|
||||||
|
.endObject().endObject().bytes();
|
||||||
|
ParsedDocument doc = mapper.parse("test", "type", "1", bytes);
|
||||||
|
assertNull(doc.dynamicMappingsUpdate());
|
||||||
|
assertNull(doc.rootDoc().getField("foo.bar"));
|
||||||
|
}
|
||||||
|
|
||||||
DocumentMapper createDummyMapping(MapperService mapperService) throws Exception {
|
DocumentMapper createDummyMapping(MapperService mapperService) throws Exception {
|
||||||
String mapping = jsonBuilder().startObject().startObject("type").startObject("properties")
|
String mapping = jsonBuilder().startObject().startObject("type").startObject("properties")
|
||||||
.startObject("y").field("type", "object").endObject()
|
.startObject("y").field("type", "object").endObject()
|
||||||
|
|
Loading…
Reference in New Issue