private static ObjectMapper parseObject( final ParseContext context, ObjectMapper mapper, String currentFieldName) throws IOException { if (currentFieldName == null) { throw new MapperParsingException( "object mapping [" + mapper.name() + "] trying to serialize an object with no field associated with it, current value [" + context.parser().textOrNull() + "]"); } context.path().add(currentFieldName); ObjectMapper update = null; Mapper objectMapper = mapper.getMapper(currentFieldName); if (objectMapper != null) { final Mapper subUpdate = parseObjectOrField(context, objectMapper); if (subUpdate != null) { // propagate mapping update update = mapper.mappingUpdate(subUpdate); } } else { ObjectMapper.Dynamic dynamic = mapper.dynamic(); if (dynamic == null) { dynamic = dynamicOrDefault(context.root().dynamic()); } if (dynamic == ObjectMapper.Dynamic.STRICT) { throw new StrictDynamicMappingException(mapper.fullPath(), currentFieldName); } else if (dynamic == ObjectMapper.Dynamic.TRUE) { // remove the current field name from path, since template search and the object builder add // it as well... context.path().remove(); Mapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, "object"); if (builder == null) { builder = MapperBuilders.object(currentFieldName).enabled(true); // if this is a non root object, then explicitly set the dynamic behavior if set if (!(mapper instanceof RootObjectMapper) && mapper.dynamic() != ObjectMapper.Defaults.DYNAMIC) { ((ObjectMapper.Builder) builder).dynamic(mapper.dynamic()); } } Mapper.BuilderContext builderContext = new Mapper.BuilderContext(context.indexSettings(), context.path()); objectMapper = builder.build(builderContext); context.path().add(currentFieldName); update = mapper.mappingUpdate(parseAndMergeUpdate(objectMapper, context)); } else { // not dynamic, read everything up to end object context.parser().skipChildren(); } } context.path().remove(); return update; }
private static void parseNullValue(ParseContext context, ObjectMapper parentMapper, String lastFieldName) throws IOException { // we can only handle null values if we have mappings for them Mapper mapper = parentMapper.getMapper(lastFieldName); if (mapper != null) { // TODO: passing null to an object seems bogus? parseObjectOrField(context, mapper); } else if (parentMapper.dynamic() == ObjectMapper.Dynamic.STRICT) { throw new StrictDynamicMappingException(parentMapper.fullPath(), lastFieldName); } }
private static ObjectMapper parseDynamicValue(final ParseContext context, ObjectMapper parentMapper, String currentFieldName, XContentParser.Token token) throws IOException { ObjectMapper.Dynamic dynamic = parentMapper.dynamic(); if (dynamic == null) { dynamic = dynamicOrDefault(context.root().dynamic()); } if (dynamic == ObjectMapper.Dynamic.STRICT) { throw new StrictDynamicMappingException(parentMapper.fullPath(), currentFieldName); } if (dynamic == ObjectMapper.Dynamic.FALSE) { return null; } final Mapper.BuilderContext builderContext = new Mapper.BuilderContext(context.indexSettings(), context.path()); final MappedFieldType existingFieldType = context.mapperService().fullName(context.path().fullPathAsText(currentFieldName)); Mapper.Builder builder = null; if (existingFieldType != null) { // create a builder of the same type builder = createBuilderFromFieldType(context, existingFieldType, currentFieldName); if (builder != null) { // best-effort to not introduce a conflict if (builder instanceof StringFieldMapper.Builder) { StringFieldMapper.Builder stringBuilder = (StringFieldMapper.Builder) builder; stringBuilder.fieldDataSettings(existingFieldType.fieldDataType().getSettings()); stringBuilder.store(existingFieldType.stored()); stringBuilder.indexOptions(existingFieldType.indexOptions()); stringBuilder.tokenized(existingFieldType.tokenized()); stringBuilder.omitNorms(existingFieldType.omitNorms()); stringBuilder.docValues(existingFieldType.hasDocValues()); stringBuilder.indexAnalyzer(existingFieldType.indexAnalyzer()); stringBuilder.searchAnalyzer(existingFieldType.searchAnalyzer()); } else if (builder instanceof NumberFieldMapper.Builder) { NumberFieldMapper.Builder<?,?> numberBuilder = (NumberFieldMapper.Builder<?, ?>) builder; numberBuilder.fieldDataSettings(existingFieldType.fieldDataType().getSettings()); numberBuilder.store(existingFieldType.stored()); numberBuilder.indexOptions(existingFieldType.indexOptions()); numberBuilder.tokenized(existingFieldType.tokenized()); numberBuilder.omitNorms(existingFieldType.omitNorms()); numberBuilder.docValues(existingFieldType.hasDocValues()); numberBuilder.precisionStep(existingFieldType.numericPrecisionStep()); } } } if (builder == null) { builder = createBuilderFromDynamicValue(context, token, currentFieldName); } Mapper mapper = builder.build(builderContext); mapper = parseAndMergeUpdate(mapper, context); ObjectMapper update = null; if (mapper != null) { update = parentMapper.mappingUpdate(mapper); } return update; }
private static ObjectMapper parseArray( ParseContext context, ObjectMapper parentMapper, String lastFieldName) throws IOException { String arrayFieldName = lastFieldName; Mapper mapper = parentMapper.getMapper(lastFieldName); if (mapper != null) { // There is a concrete mapper for this field already. Need to check if the mapper // expects an array, if so we pass the context straight to the mapper and if not // we serialize the array components if (mapper instanceof ArrayValueMapperParser) { final Mapper subUpdate = parseObjectOrField(context, mapper); if (subUpdate != null) { // propagate the mapping update return parentMapper.mappingUpdate(subUpdate); } else { return null; } } else { return parseNonDynamicArray(context, parentMapper, lastFieldName, arrayFieldName); } } else { ObjectMapper.Dynamic dynamic = parentMapper.dynamic(); if (dynamic == null) { dynamic = dynamicOrDefault(context.root().dynamic()); } if (dynamic == ObjectMapper.Dynamic.STRICT) { throw new StrictDynamicMappingException(parentMapper.fullPath(), arrayFieldName); } else if (dynamic == ObjectMapper.Dynamic.TRUE) { Mapper.Builder builder = context.root().findTemplateBuilder(context, arrayFieldName, "object"); if (builder == null) { return parseNonDynamicArray(context, parentMapper, lastFieldName, arrayFieldName); } Mapper.BuilderContext builderContext = new Mapper.BuilderContext(context.indexSettings(), context.path()); mapper = builder.build(builderContext); if (mapper != null && mapper instanceof ArrayValueMapperParser) { context.path().add(arrayFieldName); mapper = parseAndMergeUpdate(mapper, context); return parentMapper.mappingUpdate(mapper); } else { return parseNonDynamicArray(context, parentMapper, lastFieldName, arrayFieldName); } } else { return parseNonDynamicArray(context, parentMapper, lastFieldName, arrayFieldName); } } }
/** Creates an copy of the current field with given field name and boost */ private static void parseCopy(String field, ParseContext context) throws IOException { FieldMapper fieldMapper = context.docMapper().mappers().getMapper(field); if (fieldMapper != null) { fieldMapper.parse(context); } else { // The path of the dest field might be completely different from the current one so we need to // reset it context = context.overridePath(new ContentPath(0)); String[] paths = Strings.splitStringToArray(field, '.'); String fieldName = paths[paths.length - 1]; ObjectMapper mapper = context.root(); ObjectMapper[] mappers = new ObjectMapper[paths.length - 1]; if (paths.length > 1) { ObjectMapper parent = context.root(); for (int i = 0; i < paths.length - 1; i++) { mapper = context.docMapper().objectMappers().get(context.path().pathAsText(paths[i])); if (mapper == null) { // One mapping is missing, check if we are allowed to create a dynamic one. ObjectMapper.Dynamic dynamic = parent.dynamic(); if (dynamic == null) { dynamic = dynamicOrDefault(context.root().dynamic()); } switch (dynamic) { case STRICT: throw new StrictDynamicMappingException(parent.fullPath(), paths[i]); case TRUE: Mapper.Builder builder = context.root().findTemplateBuilder(context, paths[i], "object"); if (builder == null) { // if this is a non root object, then explicitly set the dynamic behavior if set if (!(parent instanceof RootObjectMapper) && parent.dynamic() != ObjectMapper.Defaults.DYNAMIC) { ((ObjectMapper.Builder) builder).dynamic(parent.dynamic()); } builder = MapperBuilders.object(paths[i]).enabled(true); } Mapper.BuilderContext builderContext = new Mapper.BuilderContext(context.indexSettings(), context.path()); mapper = (ObjectMapper) builder.build(builderContext); if (mapper.nested() != ObjectMapper.Nested.NO) { throw new MapperParsingException( "It is forbidden to create dynamic nested objects ([" + context.path().pathAsText(paths[i]) + "]) through `copy_to`"); } break; case FALSE: // Maybe we should log something to tell the user that the copy_to is ignored in // this case. break; default: throw new AssertionError("Unexpected dynamic type " + dynamic); } } context.path().add(paths[i]); mappers[i] = mapper; parent = mapper; } } ObjectMapper update = parseDynamicValue(context, mapper, fieldName, context.parser().currentToken()); assert update != null; // we are parsing a dynamic value so we necessarily created a new mapping if (paths.length > 1) { for (int i = paths.length - 2; i >= 0; i--) { ObjectMapper parent = context.root(); if (i > 0) { parent = mappers[i - 1]; } assert parent != null; update = parent.mappingUpdate(update); } } context.addDynamicMappingsUpdate(update); } }