/**
   * Writes the given {@link Map} to the given {@link DBObject} considering the given {@link
   * TypeInformation}.
   *
   * @param obj must not be {@literal null}.
   * @param dbo must not be {@literal null}.
   * @param propertyType must not be {@literal null}.
   * @return
   */
  protected DBObject writeMapInternal(
      Map<Object, Object> obj, DBObject dbo, TypeInformation<?> propertyType) {

    for (Map.Entry<Object, Object> entry : obj.entrySet()) {

      Object key = entry.getKey();
      Object val = entry.getValue();

      if (conversions.isSimpleType(key.getClass())) {

        String simpleKey = prepareMapKey(key);
        if (val == null || conversions.isSimpleType(val.getClass())) {
          writeSimpleInternal(val, dbo, simpleKey);
        } else if (val instanceof Collection || val.getClass().isArray()) {
          dbo.put(
              simpleKey,
              writeCollectionInternal(
                  asCollection(val), propertyType.getMapValueType(), new BasicDBList()));
        } else {
          DBObject newDbo = new BasicDBObject();
          TypeInformation<?> valueTypeInfo =
              propertyType.isMap() ? propertyType.getMapValueType() : ClassTypeInformation.OBJECT;
          writeInternal(val, newDbo, valueTypeInfo);
          dbo.put(simpleKey, newDbo);
        }
      } else {
        throw new MappingException("Cannot use a complex object as a key value.");
      }
    }

    return dbo;
  }
  /**
   * Reads the given {@link DBObject} into a {@link Map}. will recursively resolve nested {@link
   * Map}s as well.
   *
   * @param type the {@link Map} {@link TypeInformation} to be used to unmarshall this {@link
   *     DBObject}.
   * @param dbObject must not be {@literal null}
   * @param path must not be {@literal null}
   * @return
   */
  @SuppressWarnings("unchecked")
  protected Map<Object, Object> readMap(
      TypeInformation<?> type, DBObject dbObject, ObjectPath path) {

    Assert.notNull(dbObject, "DBObject must not be null!");
    Assert.notNull(path, "Object path must not be null!");

    Class<?> mapType = typeMapper.readType(dbObject, type).getType();

    TypeInformation<?> keyType = type.getComponentType();
    Class<?> rawKeyType = keyType == null ? null : keyType.getType();

    TypeInformation<?> valueType = type.getMapValueType();
    Class<?> rawValueType = valueType == null ? null : valueType.getType();

    Map<Object, Object> map =
        CollectionFactory.createMap(mapType, rawKeyType, dbObject.keySet().size());
    Map<String, Object> sourceMap = dbObject.toMap();

    for (Entry<String, Object> entry : sourceMap.entrySet()) {
      if (typeMapper.isTypeKey(entry.getKey())) {
        continue;
      }

      Object key = potentiallyUnescapeMapKey(entry.getKey());

      if (rawKeyType != null) {
        key = conversionService.convert(key, rawKeyType);
      }

      Object value = entry.getValue();

      if (value instanceof DBObject) {
        map.put(key, read(valueType, (DBObject) value, path));
      } else if (value instanceof DBRef) {
        map.put(
            key,
            DBRef.class.equals(rawValueType) ? value : read(valueType, readRef((DBRef) value)));
      } else {
        Class<?> valueClass = valueType == null ? null : valueType.getType();
        map.put(key, getPotentiallyConvertedSimpleRead(value, valueClass));
      }
    }

    return map;
  }