protected static void parseNested(
     String name, Map<String, Object> node, ObjectMapper.Builder builder) {
   boolean nested = false;
   boolean nestedIncludeInParent = false;
   boolean nestedIncludeInRoot = false;
   Object fieldNode = node.get("type");
   if (fieldNode != null) {
     String type = fieldNode.toString();
     if (type.equals(CONTENT_TYPE)) {
       builder.nested = Nested.NO;
     } else if (type.equals(NESTED_CONTENT_TYPE)) {
       nested = true;
     } else {
       throw new MapperParsingException(
           "Trying to parse an object but has a different type ["
               + type
               + "] for ["
               + name
               + "]");
     }
   }
   fieldNode = node.get("include_in_parent");
   if (fieldNode != null) {
     nestedIncludeInParent = nodeBooleanValue(fieldNode);
     node.remove("include_in_parent");
   }
   fieldNode = node.get("include_in_root");
   if (fieldNode != null) {
     nestedIncludeInRoot = nodeBooleanValue(fieldNode);
     node.remove("include_in_root");
   }
   if (nested) {
     builder.nested = Nested.newNested(nestedIncludeInParent, nestedIncludeInRoot);
   }
 }
 protected static boolean parseObjectOrDocumentTypeProperties(
     String fieldName,
     Object fieldNode,
     ParserContext parserContext,
     ObjectMapper.Builder builder) {
   if (fieldName.equals("dynamic")) {
     String value = fieldNode.toString();
     if (value.equalsIgnoreCase("strict")) {
       builder.dynamic(Dynamic.STRICT);
     } else {
       builder.dynamic(nodeBooleanValue(fieldNode) ? Dynamic.TRUE : Dynamic.FALSE);
     }
     return true;
   } else if (fieldName.equals("enabled")) {
     builder.enabled(nodeBooleanValue(fieldNode));
     return true;
   } else if (fieldName.equals("properties")) {
     if (fieldNode instanceof Collection && ((Collection) fieldNode).isEmpty()) {
       // nothing to do here, empty (to support "properties: []" case)
     } else if (!(fieldNode instanceof Map)) {
       throw new ElasticsearchParseException("properties must be a map type");
     } else {
       parseProperties(builder, (Map<String, Object>) fieldNode, parserContext);
     }
     return true;
   } else if (fieldName.equals("include_in_all")) {
     builder.includeInAll(nodeBooleanValue(fieldNode));
     return true;
   }
   return false;
 }
    private void parseProperties(
        ObjectMapper.Builder objBuilder,
        Map<String, Object> propsNode,
        ParserContext parserContext) {
      for (Map.Entry<String, Object> entry : propsNode.entrySet()) {
        String propName = entry.getKey();
        Map<String, Object> propNode = (Map<String, Object>) entry.getValue();

        String type;
        Object typeNode = propNode.get("type");
        if (typeNode != null) {
          type = typeNode.toString();
        } else {
          // lets see if we can derive this...
          if (propNode.get("properties") != null) {
            type = ObjectMapper.CONTENT_TYPE;
          } else if (propNode.get("fields") != null) {
            type = MultiFieldMapper.CONTENT_TYPE;
          } else {
            throw new MapperParsingException("No type specified for property [" + propName + "]");
          }
        }

        Mapper.TypeParser typeParser = parserContext.typeParser(type);
        if (typeParser == null) {
          throw new MapperParsingException(
              "No handler for type [" + type + "] declared on field [" + propName + "]");
        }
        objBuilder.add(typeParser.parse(propName, propNode, parserContext));
      }
    }
    @Override
    public Mapper.Builder parse(String name, Map<String, Object> node, ParserContext parserContext)
        throws MapperParsingException {
      Map<String, Object> objectNode = node;
      ObjectMapper.Builder builder = createBuilder(name);

      boolean nested = false;
      boolean nestedIncludeInParent = false;
      boolean nestedIncludeInRoot = false;
      for (Map.Entry<String, Object> entry : objectNode.entrySet()) {
        String fieldName = Strings.toUnderscoreCase(entry.getKey());
        Object fieldNode = entry.getValue();

        if (fieldName.equals("dynamic")) {
          String value = fieldNode.toString();
          if (value.equalsIgnoreCase("strict")) {
            builder.dynamic(Dynamic.STRICT);
          } else {
            builder.dynamic(nodeBooleanValue(fieldNode) ? Dynamic.TRUE : Dynamic.FALSE);
          }
        } else if (fieldName.equals("type")) {
          String type = fieldNode.toString();
          if (type.equals(CONTENT_TYPE)) {
            builder.nested = Nested.NO;
          } else if (type.equals(NESTED_CONTENT_TYPE)) {
            nested = true;
          } else {
            throw new MapperParsingException(
                "Trying to parse an object but has a different type ["
                    + type
                    + "] for ["
                    + name
                    + "]");
          }
        } else if (fieldName.equals("include_in_parent")) {
          nestedIncludeInParent = nodeBooleanValue(fieldNode);
        } else if (fieldName.equals("include_in_root")) {
          nestedIncludeInRoot = nodeBooleanValue(fieldNode);
        } else if (fieldName.equals("enabled")) {
          builder.enabled(nodeBooleanValue(fieldNode));
        } else if (fieldName.equals("path")) {
          builder.pathType(parsePathType(name, fieldNode.toString()));
        } else if (fieldName.equals("properties")) {
          parseProperties(builder, (Map<String, Object>) fieldNode, parserContext);
        } else if (fieldName.equals("include_in_all")) {
          builder.includeInAll(nodeBooleanValue(fieldNode));
        } else {
          processField(builder, fieldName, fieldNode);
        }
      }

      if (nested) {
        builder.nested = Nested.newNested(nestedIncludeInParent, nestedIncludeInRoot);
      }

      return builder;
    }
  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;
  }
 protected static boolean parseObjectProperties(
     String name,
     String fieldName,
     Object fieldNode,
     ParserContext parserContext,
     ObjectMapper.Builder builder) {
   if (fieldName.equals("path") && parserContext.indexVersionCreated().before(Version.V_2_0_0)) {
     builder.pathType(parsePathType(name, fieldNode.toString()));
     return true;
   }
   return false;
 }
    protected static void parseProperties(
        ObjectMapper.Builder objBuilder,
        Map<String, Object> propsNode,
        ParserContext parserContext) {
      for (Map.Entry<String, Object> entry : propsNode.entrySet()) {
        String propName = entry.getKey();
        // Should accept empty arrays, as a work around for when the user can't provide an empty
        // Map. (PHP for example)
        boolean isEmptyList =
            entry.getValue() instanceof List && ((List<?>) entry.getValue()).isEmpty();

        if (entry.getValue() instanceof Map) {
          @SuppressWarnings("unchecked")
          Map<String, Object> propNode = (Map<String, Object>) entry.getValue();
          String type;
          Object typeNode = propNode.get("type");
          if (typeNode != null) {
            type = typeNode.toString();
          } else {
            // lets see if we can derive this...
            if (propNode.get("properties") != null) {
              type = ObjectMapper.CONTENT_TYPE;
            } else if (propNode.size() == 1 && propNode.get("enabled") != null) {
              // if there is a single property with the enabled flag on it, make it an object
              // (usually, setting enabled to false to not index any type, including core values,
              // which
              // non enabled object type supports).
              type = ObjectMapper.CONTENT_TYPE;
            } else {
              throw new MapperParsingException("No type specified for property [" + propName + "]");
            }
          }

          Mapper.TypeParser typeParser = parserContext.typeParser(type);
          if (typeParser == null) {
            throw new MapperParsingException(
                "No handler for type [" + type + "] declared on field [" + propName + "]");
          }
          objBuilder.add(typeParser.parse(propName, propNode, parserContext));
        } else if (!isEmptyList) {
          throw new MapperParsingException(
              "Expected map for property [fields] on field ["
                  + propName
                  + "] but got a "
                  + propName.getClass());
        }
      }
    }
    private void parseProperties(
        ObjectMapper.Builder objBuilder,
        Map<String, Object> propsNode,
        ParserContext parserContext) {
      for (Map.Entry<String, Object> entry : propsNode.entrySet()) {
        String propName = entry.getKey();
        Map<String, Object> propNode = (Map<String, Object>) entry.getValue();

        String type;
        Object typeNode = propNode.get("type");
        if (typeNode != null) {
          type = typeNode.toString();
        } else {
          // lets see if we can derive this...
          if (propNode.get("properties") != null) {
            type = ObjectMapper.CONTENT_TYPE;
          } else if (propNode.get("fields") != null) {
            type = MultiFieldMapper.CONTENT_TYPE;
          } else if (propNode.size() == 1 && propNode.get("enabled") != null) {
            // if there is a single property with the enabled flag on it, make it an object
            // (usually, setting enabled to false to not index any type, including core values,
            // which
            // non enabled object type supports).
            type = ObjectMapper.CONTENT_TYPE;
          } else {
            throw new MapperParsingException("No type specified for property [" + propName + "]");
          }
        }

        Mapper.TypeParser typeParser = parserContext.typeParser(type);
        if (typeParser == null) {
          throw new MapperParsingException(
              "No handler for type [" + type + "] declared on field [" + propName + "]");
        }
        objBuilder.add(typeParser.parse(propName, propNode, parserContext));
      }
    }
    protected static void parseProperties(
        ObjectMapper.Builder objBuilder,
        Map<String, Object> propsNode,
        ParserContext parserContext) {
      Iterator<Map.Entry<String, Object>> iterator = propsNode.entrySet().iterator();
      while (iterator.hasNext()) {
        Map.Entry<String, Object> entry = iterator.next();
        String propName = entry.getKey();
        // Should accept empty arrays, as a work around for when the
        // user can't provide an empty Map. (PHP for example)
        boolean isEmptyList =
            entry.getValue() instanceof List && ((List<?>) entry.getValue()).isEmpty();

        if (entry.getValue() instanceof Map) {
          @SuppressWarnings("unchecked")
          Map<String, Object> propNode = (Map<String, Object>) entry.getValue();
          String type;
          Object typeNode = propNode.get("type");
          if (typeNode != null) {
            type = typeNode.toString();
          } else {
            // lets see if we can derive this...
            if (propNode.get("properties") != null) {
              type = ObjectMapper.CONTENT_TYPE;
            } else if (propNode.size() == 1 && propNode.get("enabled") != null) {
              // if there is a single property with the enabled
              // flag on it, make it an object
              // (usually, setting enabled to false to not index
              // any type, including core values, which
              type = ObjectMapper.CONTENT_TYPE;
            } else {
              throw new MapperParsingException("No type specified for property [" + propName + "]");
            }
          }

          Mapper.TypeParser typeParser = parserContext.typeParser(type);
          if (typeParser == null) {
            throw new MapperParsingException(
                "No handler for type [" + type + "] declared on field [" + propName + "]");
          }
          objBuilder.add(typeParser.parse(propName, propNode, parserContext));
          propNode.remove("type");
          DocumentMapperParser.checkNoRemainingFields(
              propName, propNode, parserContext.indexVersionCreated());
          iterator.remove();
        } else if (isEmptyList) {
          iterator.remove();
        } else {
          throw new MapperParsingException(
              "Expected map for property [fields] on field ["
                  + propName
                  + "] but got a "
                  + propName.getClass());
        }
      }

      DocumentMapperParser.checkNoRemainingFields(
          propsNode,
          parserContext.indexVersionCreated(),
          "DocType mapping definition has unsupported parameters: ");
    }
  /** 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);
    }
  }
 protected static void parseObjectProperties(
     String name, String fieldName, Object fieldNode, ObjectMapper.Builder builder) {
   if (fieldName.equals("path")) {
     builder.pathType(parsePathType(name, fieldNode.toString()));
   }
 }