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;
    }
 @Override
 public Mapper.Builder parse(String name, Map<String, Object> node, ParserContext parserContext)
     throws MapperParsingException {
   StringFieldMapper.Builder builder = stringField(name);
   parseField(builder, name, node, parserContext);
   for (Iterator<Map.Entry<String, Object>> iterator = node.entrySet().iterator();
       iterator.hasNext(); ) {
     Map.Entry<String, Object> entry = iterator.next();
     String propName = Strings.toUnderscoreCase(entry.getKey());
     Object propNode = entry.getValue();
     if (propName.equals("null_value")) {
       if (propNode == null) {
         throw new MapperParsingException("Property [null_value] cannot be null.");
       }
       builder.nullValue(propNode.toString());
       iterator.remove();
     } else if (propName.equals("search_quote_analyzer")) {
       NamedAnalyzer analyzer = parserContext.analysisService().analyzer(propNode.toString());
       if (analyzer == null) {
         throw new MapperParsingException(
             "Analyzer [" + propNode.toString() + "] not found for field [" + name + "]");
       }
       builder.searchQuotedAnalyzer(analyzer);
       iterator.remove();
     } else if (propName.equals("position_offset_gap")) {
       builder.positionOffsetGap(XContentMapValues.nodeIntegerValue(propNode, -1));
       // we need to update to actual analyzers if they are not set in this case...
       // so we can inject the position offset gap...
       if (builder.indexAnalyzer == null) {
         builder.indexAnalyzer = parserContext.analysisService().defaultIndexAnalyzer();
       }
       if (builder.searchAnalyzer == null) {
         builder.searchAnalyzer = parserContext.analysisService().defaultSearchAnalyzer();
       }
       if (builder.searchQuotedAnalyzer == null) {
         builder.searchQuotedAnalyzer =
             parserContext.analysisService().defaultSearchQuoteAnalyzer();
       }
       iterator.remove();
     } else if (propName.equals("ignore_above")) {
       builder.ignoreAbove(XContentMapValues.nodeIntegerValue(propNode, -1));
       iterator.remove();
     } else if (parseMultiField(builder, name, parserContext, propName, propNode)) {
       iterator.remove();
     }
   }
   return builder;
 }
 @Override
 public Mapper.Builder parse(
     String fieldName, Map<String, Object> node, ParserContext parserContext)
     throws MapperParsingException {
   StringFieldMapper.Builder builder = new StringFieldMapper.Builder(fieldName);
   // hack for the fact that string can't just accept true/false for
   // the index property and still accepts no/not_analyzed/analyzed
   final Object index = node.remove("index");
   if (index != null) {
     final String normalizedIndex = Strings.toUnderscoreCase(index.toString());
     switch (normalizedIndex) {
       case "analyzed":
         builder.tokenized(true);
         node.put("index", true);
         break;
       case "not_analyzed":
         builder.tokenized(false);
         node.put("index", true);
         break;
       case "no":
         node.put("index", false);
         break;
       default:
         throw new IllegalArgumentException(
             "Can't parse [index] value ["
                 + index
                 + "] for field ["
                 + fieldName
                 + "], expected [true], [false], [no], [not_analyzed] or [analyzed]");
     }
   }
   parseTextField(builder, fieldName, node, parserContext);
   for (Iterator<Map.Entry<String, Object>> iterator = node.entrySet().iterator();
       iterator.hasNext(); ) {
     Map.Entry<String, Object> entry = iterator.next();
     String propName = Strings.toUnderscoreCase(entry.getKey());
     Object propNode = entry.getValue();
     if (propName.equals("null_value")) {
       if (propNode == null) {
         throw new MapperParsingException("Property [null_value] cannot be null.");
       }
       builder.nullValue(propNode.toString());
       iterator.remove();
     } else if (propName.equals("position_increment_gap")) {
       int newPositionIncrementGap = XContentMapValues.nodeIntegerValue(propNode, -1);
       if (newPositionIncrementGap < 0) {
         throw new MapperParsingException("positions_increment_gap less than 0 aren't allowed.");
       }
       builder.positionIncrementGap(newPositionIncrementGap);
       // we need to update to actual analyzers if they are not set in this case...
       // so we can inject the position increment gap...
       if (builder.fieldType().indexAnalyzer() == null) {
         builder
             .fieldType()
             .setIndexAnalyzer(parserContext.analysisService().defaultIndexAnalyzer());
       }
       if (builder.fieldType().searchAnalyzer() == null) {
         builder
             .fieldType()
             .setSearchAnalyzer(parserContext.analysisService().defaultSearchAnalyzer());
       }
       if (builder.fieldType().searchQuoteAnalyzer() == null) {
         builder
             .fieldType()
             .setSearchQuoteAnalyzer(
                 parserContext.analysisService().defaultSearchQuoteAnalyzer());
       }
       iterator.remove();
     } else if (propName.equals("ignore_above")) {
       builder.ignoreAbove(XContentMapValues.nodeIntegerValue(propNode, -1));
       iterator.remove();
     } else if (parseMultiField(builder, fieldName, parserContext, propName, propNode)) {
       iterator.remove();
     }
   }
   return builder;
 }