private void serializeObject(final ParseContext context, String currentFieldName) throws IOException { if (currentFieldName == null) { throw new MapperParsingException( "object mapping [" + name + "] trying to serialize an object with no field associated with it, current value [" + context.parser().textOrNull() + "]"); } context.path().add(currentFieldName); Mapper objectMapper = mappers.get(currentFieldName); if (objectMapper != null) { objectMapper.parse(context); } else { Dynamic dynamic = this.dynamic; if (dynamic == null) { dynamic = context.root().dynamic(); } if (dynamic == Dynamic.STRICT) { throw new StrictDynamicMappingException(fullPath, currentFieldName); } else if (dynamic == Dynamic.TRUE) { // we sync here just so we won't add it twice. Its not the end of the world // to sync here since next operations will get it before synchronized (mutex) { objectMapper = mappers.get(currentFieldName); if (objectMapper == null) { // 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).pathType(pathType); // if this is a non root object, then explicitly set the dynamic behavior if set if (!(this instanceof RootObjectMapper) && this.dynamic != Defaults.DYNAMIC) { ((Builder) builder).dynamic(this.dynamic); } } BuilderContext builderContext = new BuilderContext(context.indexSettings(), context.path()); objectMapper = builder.build(builderContext); putDynamicMapper(context, currentFieldName, objectMapper); } else { objectMapper.parse(context); } } } else { // not dynamic, read everything up to end object context.parser().skipChildren(); } } context.path().remove(); }
private void serializeArray(ParseContext context, String lastFieldName) throws IOException { String arrayFieldName = lastFieldName; Mapper mapper = mappers.get(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) { mapper.parse(context); } else { serializeNonDynamicArray(context, lastFieldName, arrayFieldName); } } else { Dynamic dynamic = this.dynamic; if (dynamic == null) { dynamic = context.root().dynamic(); } if (dynamic == Dynamic.STRICT) { throw new StrictDynamicMappingException(fullPath, arrayFieldName); } else if (dynamic == Dynamic.TRUE) { // we sync here just so we won't add it twice. Its not the end of the world // to sync here since next operations will get it before synchronized (mutex) { mapper = mappers.get(arrayFieldName); if (mapper == null) { Mapper.Builder builder = context.root().findTemplateBuilder(context, arrayFieldName, "object"); if (builder == null) { serializeNonDynamicArray(context, lastFieldName, arrayFieldName); return; } BuilderContext builderContext = new BuilderContext(context.indexSettings(), context.path()); mapper = builder.build(builderContext); if (mapper != null && mapper instanceof ArrayValueMapperParser) { putDynamicMapper(context, arrayFieldName, mapper); } else { serializeNonDynamicArray(context, lastFieldName, arrayFieldName); } } else { serializeNonDynamicArray(context, lastFieldName, arrayFieldName); } } } else { serializeNonDynamicArray(context, lastFieldName, arrayFieldName); } } }
private Analyzer getAnalyzer(String name) { Analyzer analyzer = analyzers.get(name); if (analyzer != null) { return analyzer; } // Don't be lenient here and return the default analyzer // Fields need to be explicitly added throw new IllegalArgumentException("Field [" + name + "] has no associated analyzer"); }
private void serializeNullValue(ParseContext context, String lastFieldName) throws IOException { // we can only handle null values if we have mappings for them Mapper mapper = mappers.get(lastFieldName); if (mapper != null) { if (mapper instanceof FieldMapper) { if (!((FieldMapper) mapper).supportsNullValue()) { throw new MapperParsingException( "no object mapping found for null value in [" + lastFieldName + "]"); } } mapper.parse(context); } }
private void serializeValue( final ParseContext context, String currentFieldName, XContentParser.Token token) throws IOException { if (currentFieldName == null) { throw new MapperParsingException( "object mapping [" + name + "] trying to serialize a value with no field associated with it, current value [" + context.parser().textOrNull() + "]"); } Mapper mapper = mappers.get(currentFieldName); if (mapper != null) { mapper.parse(context); } else { parseDynamicValue(context, currentFieldName, token); } }
@Override public void merge(final Mapper mergeWith, final MergeResult mergeResult) throws MergeMappingException { if (!(mergeWith instanceof ObjectMapper)) { mergeResult.addConflict( "Can't merge a non object mapping [" + mergeWith.name() + "] with an object mapping [" + name() + "]"); return; } ObjectMapper mergeWithObject = (ObjectMapper) mergeWith; if (nested().isNested()) { if (!mergeWithObject.nested().isNested()) { mergeResult.addConflict( "object mapping [" + name() + "] can't be changed from nested to non-nested"); return; } } else { if (mergeWithObject.nested().isNested()) { mergeResult.addConflict( "object mapping [" + name() + "] can't be changed from non-nested to nested"); return; } } if (!mergeResult.simulate()) { if (mergeWithObject.dynamic != null) { this.dynamic = mergeWithObject.dynamic; } } doMerge(mergeWithObject, mergeResult); List<Mapper> mappersToPut = new ArrayList<>(); List<ObjectMapper> newObjectMappers = new ArrayList<>(); List<FieldMapper> newFieldMappers = new ArrayList<>(); for (Mapper mapper : mergeWithObject) { Mapper mergeWithMapper = mapper; Mapper mergeIntoMapper = mappers.get(mergeWithMapper.simpleName()); if (mergeIntoMapper == null) { // no mapping, simply add it if not simulating if (!mergeResult.simulate()) { mappersToPut.add(mergeWithMapper); MapperUtils.collect(mergeWithMapper, newObjectMappers, newFieldMappers); } } else if (mergeIntoMapper instanceof MetadataFieldMapper == false) { // root mappers can only exist here for backcompat, and are merged in Mapping mergeIntoMapper.merge(mergeWithMapper, mergeResult); } } if (!newFieldMappers.isEmpty()) { mergeResult.addFieldMappers(newFieldMappers); } if (!newObjectMappers.isEmpty()) { mergeResult.addObjectMappers(newObjectMappers); } // add the mappers only after the administration have been done, so it will not be visible to // parser (which first try to read with no lock) for (Mapper mapper : mappersToPut) { putMapper(mapper); } }
public Mapper getMapper(String field) { return mappers.get(field); }
public void parseDynamicValue( final ParseContext context, String currentFieldName, XContentParser.Token token) throws IOException { Dynamic dynamic = this.dynamic; if (dynamic == null) { dynamic = context.root().dynamic(); } if (dynamic == Dynamic.STRICT) { throw new StrictDynamicMappingException(fullPath, currentFieldName); } if (dynamic == Dynamic.FALSE) { return; } // we sync here since we don't want to add this field twice to the document mapper // its not the end of the world, since we add it to the mappers once we create it // so next time we won't even get here for this field synchronized (mutex) { Mapper mapper = mappers.get(currentFieldName); if (mapper == null) { BuilderContext builderContext = new BuilderContext(context.indexSettings(), context.path()); if (token == XContentParser.Token.VALUE_STRING) { boolean resolved = false; // do a quick test to see if its fits a dynamic template, if so, use it. // we need to do it here so we can handle things like attachment templates, where calling // text (to see if its a date) causes the binary value to be cleared if (!resolved) { Mapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, "string", null); if (builder != null) { mapper = builder.build(builderContext); resolved = true; } } if (!resolved && context.parser().textLength() == 0) { // empty string with no mapping, treat it like null value return; } if (!resolved && context.root().dateDetection()) { String text = context.parser().text(); // a safe check since "1" gets parsed as well if (Strings.countOccurrencesOf(text, ":") > 1 || Strings.countOccurrencesOf(text, "-") > 1 || Strings.countOccurrencesOf(text, "/") > 1) { for (FormatDateTimeFormatter dateTimeFormatter : context.root().dynamicDateTimeFormatters()) { try { dateTimeFormatter.parser().parseMillis(text); Mapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, "date"); if (builder == null) { builder = dateField(currentFieldName).dateTimeFormatter(dateTimeFormatter); } mapper = builder.build(builderContext); resolved = true; break; } catch (Exception e) { // failure to parse this, continue } } } } if (!resolved && context.root().numericDetection()) { String text = context.parser().text(); try { Long.parseLong(text); Mapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, "long"); if (builder == null) { builder = longField(currentFieldName); } mapper = builder.build(builderContext); resolved = true; } catch (Exception e) { // not a long number } if (!resolved) { try { Double.parseDouble(text); Mapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, "double"); if (builder == null) { builder = doubleField(currentFieldName); } mapper = builder.build(builderContext); resolved = true; } catch (Exception e) { // not a long number } } } if (!resolved) { Mapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, "string"); if (builder == null) { builder = stringField(currentFieldName); } mapper = builder.build(builderContext); } } else if (token == XContentParser.Token.VALUE_NUMBER) { XContentParser.NumberType numberType = context.parser().numberType(); if (numberType == XContentParser.NumberType.INT) { if (context.parser().estimatedNumberType()) { Mapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, "long"); if (builder == null) { builder = longField(currentFieldName); } mapper = builder.build(builderContext); } else { Mapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, "integer"); if (builder == null) { builder = integerField(currentFieldName); } mapper = builder.build(builderContext); } } else if (numberType == XContentParser.NumberType.LONG) { Mapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, "long"); if (builder == null) { builder = longField(currentFieldName); } mapper = builder.build(builderContext); } else if (numberType == XContentParser.NumberType.FLOAT) { if (context.parser().estimatedNumberType()) { Mapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, "double"); if (builder == null) { builder = doubleField(currentFieldName); } mapper = builder.build(builderContext); } else { Mapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, "float"); if (builder == null) { builder = floatField(currentFieldName); } mapper = builder.build(builderContext); } } else if (numberType == XContentParser.NumberType.DOUBLE) { Mapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, "double"); if (builder == null) { builder = doubleField(currentFieldName); } mapper = builder.build(builderContext); } } else if (token == XContentParser.Token.VALUE_BOOLEAN) { Mapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, "boolean"); if (builder == null) { builder = booleanField(currentFieldName); } mapper = builder.build(builderContext); } else if (token == XContentParser.Token.VALUE_EMBEDDED_OBJECT) { Mapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, "binary"); if (builder == null) { builder = binaryField(currentFieldName); } mapper = builder.build(builderContext); } else { Mapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, null); if (builder != null) { mapper = builder.build(builderContext); } else { // TODO how do we identify dynamically that its a binary value? throw new ElasticsearchIllegalStateException( "Can't handle serializing a dynamic type with content token [" + token + "] and field name [" + currentFieldName + "]"); } } if (context.isWithinNewMapper()) { mapper.parse(context); } else { context.setWithinNewMapper(); try { mapper.parse(context); FieldMapperListener.Aggregator newFields = new FieldMapperListener.Aggregator(); mapper.traverse(newFields); context.docMapper().addFieldMappers(newFields.mappers); } finally { context.clearWithinNewMapper(); } } // only put after we traversed and did the callbacks, so other parsing won't see it only // after we // properly traversed it and adding the mappers putMapper(mapper); context.setMappingsModified(); } else { mapper.parse(context); } } }
@Override public void merge(final Mapper mergeWith, final MergeContext mergeContext) throws MergeMappingException { if (!(mergeWith instanceof ObjectMapper)) { mergeContext.addConflict( "Can't merge a non object mapping [" + mergeWith.name() + "] with an object mapping [" + name() + "]"); return; } ObjectMapper mergeWithObject = (ObjectMapper) mergeWith; if (nested().isNested()) { if (!mergeWithObject.nested().isNested()) { mergeContext.addConflict( "object mapping [" + name() + "] can't be changed from nested to non-nested"); return; } } else { if (mergeWithObject.nested().isNested()) { mergeContext.addConflict( "object mapping [" + name() + "] can't be changed from non-nested to nested"); return; } } if (!mergeContext.mergeFlags().simulate()) { if (mergeWithObject.dynamic != null) { this.dynamic = mergeWithObject.dynamic; } } doMerge(mergeWithObject, mergeContext); List<Mapper> mappersToPut = new ArrayList<>(); FieldMapperListener.Aggregator newFieldMappers = new FieldMapperListener.Aggregator(); ObjectMapperListener.Aggregator newObjectMappers = new ObjectMapperListener.Aggregator(); synchronized (mutex) { for (Mapper mapper : mergeWithObject.mappers.values()) { Mapper mergeWithMapper = mapper; Mapper mergeIntoMapper = mappers.get(mergeWithMapper.name()); if (mergeIntoMapper == null) { // no mapping, simply add it if not simulating if (!mergeContext.mergeFlags().simulate()) { mappersToPut.add(mergeWithMapper); mergeWithMapper.traverse(newFieldMappers); mergeWithMapper.traverse(newObjectMappers); } } else { mergeIntoMapper.merge(mergeWithMapper, mergeContext); } } if (!newFieldMappers.mappers.isEmpty()) { mergeContext.docMapper().addFieldMappers(newFieldMappers.mappers); } if (!newObjectMappers.mappers.isEmpty()) { mergeContext.docMapper().addObjectMappers(newObjectMappers.mappers); } // and the mappers only after the administration have been done, so it will not be visible to // parser (which first try to read with no lock) for (Mapper mapper : mappersToPut) { putMapper(mapper); } } }