@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;
 }