@Override
    public Y build(BuilderContext context) {
      ContentPath.Type origPathType = context.path().pathType();
      context.path().pathType(pathType);
      context.path().add(name);

      Map<String, Mapper> mappers = new HashMap<>();
      for (Mapper.Builder builder : mappersBuilders) {
        Mapper mapper = builder.build(context);
        mappers.put(mapper.simpleName(), mapper);
      }
      context.path().pathType(origPathType);
      context.path().remove();

      ObjectMapper objectMapper =
          createMapper(
              name,
              context.path().fullPathAsText(name),
              enabled,
              nested,
              dynamic,
              pathType,
              mappers,
              context.indexSettings());
      objectMapper.includeInAllIfNotSet(includeInAll);

      return (Y) objectMapper;
    }
  @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);
    }
  }
 /**
  * Put a new mapper. NOTE: this method must be called under the current {@link DocumentMapper}
  * lock if concurrent updates are expected.
  */
 public void putMapper(Mapper mapper) {
   if (mapper instanceof AllFieldMapper.IncludeInAll) {
     ((AllFieldMapper.IncludeInAll) mapper).includeInAllIfNotSet(includeInAll);
   }
   mappers = mappers.copyAndPut(mapper.simpleName(), mapper);
 }