function resolveFormParamSchema (schema, schemaKey, encodingObj, requestParams, metaInfo, components, options,
  shouldIterateChildren) {

  let resolvedSchemaParams = [],
    resolvedProp,
    encodingValue,
    pSerialisationInfo,
    isPropSeparable;

  if (_.isArray(schema.anyOf) || _.isArray(schema.oneOf)) {
    _.forEach(schema.anyOf || schema.oneOf, (schemaElement) => {
      // As for such schemas there can be multiple choices, keep them as non required
      resolvedSchemaParams = _.concat(resolvedSchemaParams, resolveFormParamSchema(schemaElement, schemaKey,
        encodingObj, requestParams, _.assign(metaInfo, { required: false, isComposite: true }),
        components, options, shouldIterateChildren));
    });

    return resolvedSchemaParams;
  }

  resolvedProp = {
    name: schemaKey,
    schema: schema,
    required: _.get(metaInfo, 'required'),
    in: 'query', // serialization follows same behaviour as query params
    description: _.get(schema, 'description', _.get(metaInfo, 'description', '')),
    pathPrefix: _.get(metaInfo, 'pathPrefix'),
    isComposite: _.get(metaInfo, 'isComposite', false),
    deprecated: _.get(schema, 'deprecated', _.get(metaInfo, 'deprecated'))
  };
  encodingValue = _.get(encodingObj, schemaKey);

  if (_.isObject(encodingValue)) {
    _.has(encodingValue, 'style') && (resolvedProp.style = encodingValue.style);
    _.has(encodingValue, 'explode') && (resolvedProp.explode = encodingValue.explode);
  }

  pSerialisationInfo = getParamSerialisationInfo(resolvedProp, PARAMETER_SOURCE.REQUEST,
    components, options);
  isPropSeparable = _.includes(['form', 'deepObject'], pSerialisationInfo.style);

  /**
   * schema apart from type object should be only resolved if corresponding schema key is present.
   * i.e. As URL encoded body requires key-value pair, non key schemas should not be resolved.
   */
  if (!isPropSeparable || (!_.includes(['object', 'array'], _.get(schema, 'type')) && !_.isEmpty(schemaKey)) ||
    (_.isEmpty(schemaKey) && _.get(schema, 'type') === 'array') || !pSerialisationInfo.explode) {
    resolvedSchemaParams.push(resolvedProp);
  }
  else if (_.get(schema, 'type') === 'array' && pSerialisationInfo.style === 'form' &&
    pSerialisationInfo.explode) {

    resolvedProp.schema = _.get(schema, 'items', {});
    resolvedSchemaParams.push(resolvedProp);
  }
  else {
    // resolve each property as separate param similar to query params
    _.forEach(_.get(schema, 'properties'), (propSchema, propName) => {
      let resolvedPropName = _.isEmpty(schemaKey) ? propName : `${schemaKey}[${propName}]`,
        resolvedProp = {
          name: resolvedPropName,
          schema: propSchema,
          in: 'query', // serialization follows same behaviour as query params
          description: _.get(propSchema, 'description') || _.get(metaInfo, 'description') || '',
          required: _.get(metaInfo, 'required'),
          isComposite: _.get(metaInfo, 'isComposite', false),
          deprecated: _.get(propSchema, 'deprecated') || _.get(metaInfo, 'deprecated')
        },
        parentPropName = resolvedPropName.indexOf('[') === -1 ? resolvedPropName :
          resolvedPropName.slice(0, resolvedPropName.indexOf('[')),
        encodingValue = _.get(encodingObj, parentPropName),
        pSerialisationInfo,
        isPropSeparable;

      if (_.isObject(encodingValue)) {
        _.has(encodingValue, 'style') && (resolvedProp.style = encodingValue.style);
        _.has(encodingValue, 'explode') && (resolvedProp.explode = encodingValue.explode);
      }

      if (_.isUndefined(metaInfo.required) && _.includes(_.get(schema, 'required'), propName)) {
        resolvedProp.required = true;
      }

      pSerialisationInfo = getParamSerialisationInfo(resolvedProp, PARAMETER_SOURCE.REQUEST,
        components, options);
      isPropSeparable = _.includes(['form', 'deepObject'], pSerialisationInfo.style);

      if (_.isArray(propSchema.anyOf) || _.isArray(propSchema.oneOf)) {
        _.forEach(propSchema.anyOf || propSchema.oneOf, (schemaElement) => {
          let nextSchemaKey = _.isEmpty(schemaKey) ? propName : `${schemaKey}[${propName}]`;

          resolvedSchemaParams = _.concat(resolvedSchemaParams, resolveFormParamSchema(schemaElement, nextSchemaKey,
            encodingObj, requestParams, _.assign(metaInfo, { required: false, isComposite: true }),
            components, options, pSerialisationInfo.style === 'deepObject'));
        });

        return resolvedSchemaParams;
      }

      if (isPropSeparable && propSchema.type === 'array' && pSerialisationInfo.explode) {
        /**
         * avoid validation of complex array type param as OAS doesn't define serialisation
         * of Array with deepObject style
         */
        if (pSerialisationInfo.style !== 'deepObject' &&
          !_.includes(['array', 'object'], _.get(propSchema, 'items.type'))) {
          // add schema of corresponding items instead array
          resolvedSchemaParams.push(_.assign({}, resolvedProp, {
            schema: _.get(propSchema, 'items'),
            isResolvedParam: true
          }));
        }
      }
      else if (isPropSeparable && propSchema.type === 'object' && pSerialisationInfo.explode) {
        let localMetaInfo = _.isEmpty(metaInfo) ? (metaInfo = {
            required: resolvedProp.required,
            description: resolvedProp.description,
            deprecated: _.get(resolvedProp, 'deprecated')
          }) : metaInfo,
          nextSchemaKey = _.isEmpty(schemaKey) ? propName : `${schemaKey}[${propName}]`;

        // resolve all child params of parent param with deepObject style
        if (pSerialisationInfo.style === 'deepObject') {
          resolvedSchemaParams = _.concat(resolvedSchemaParams, resolveFormParamSchema(propSchema, nextSchemaKey,
            encodingObj, requestParams, localMetaInfo, components, options, true));
        }
        else {
          // add schema of all properties instead entire object
          _.forEach(_.get(propSchema, 'properties', {}), (value, key) => {
            resolvedSchemaParams.push({
              name: key,
              schema: value,
              isResolvedParam: true,
              required: resolvedProp.required,
              description: resolvedProp.description,
              isComposite: _.get(metaInfo, 'isComposite', false),
              deprecated: _.get(resolvedProp, 'deprecated') || _.get(metaInfo, 'deprecated')
            });
          });
        }
      }
      else {
        resolvedSchemaParams.push(resolvedProp);
      }
    });

    // Resolve additionalProperties via first finding additionalProper
    if (_.isObject(_.get(schema, 'additionalProperties'))) {
      const additionalPropSchema = _.get(schema, 'additionalProperties'),
        matchingRequestParamKeys = [];

      /**
       * Find matching keys from request param as additional props can be unknown keys.
       * and these unknown key names are not mentioned in schema
       */
      _.forEach(requestParams, ({ key }) => {
        if (_.isString(key) && schemaKey === '') {
          const isParamResolved = _.some(resolvedSchemaParams, (param) => {
            return key === param.key;
          });
          !isParamResolved && (matchingRequestParamKeys.push(key));
        }
        else if (_.isString(key) && _.startsWith(key, schemaKey + '[') && _.endsWith(key, ']')) {
          const childKey = key.substring(key.indexOf(schemaKey + '[') + schemaKey.length + 1, key.length - 1);

          if (!_.includes(childKey, '[')) {
            matchingRequestParamKeys.push(key);
          }
          else {
            matchingRequestParamKeys.push(schemaKey + '[' + childKey.slice(0, childKey.indexOf('[')));
          }
        }
      });

      // For every matched request param key add a child param schema that can be validated further
      _.forEach(matchingRequestParamKeys, (matchedRequestParamKey) => {
        if (_.get(additionalPropSchema, 'type') === 'object' && shouldIterateChildren) {
          resolvedSchemaParams = _.concat(resolvedSchemaParams, resolveFormParamSchema(additionalPropSchema,
            matchedRequestParamKey, encodingObj, requestParams, metaInfo, components, options, shouldIterateChildren));
        }

        // Avoid adding invalid array child params, As deepObject style should only contain object or simple types
        else if (_.get(additionalPropSchema, 'type') !== 'array') {
          resolvedSchemaParams.push({
            name: matchedRequestParamKey,
            schema: additionalPropSchema,
            description: _.get(additionalPropSchema, 'description') || _.get(metaInfo, 'description') || '',
            required: false,
            isResolvedParam: true,
            isComposite: true,
            deprecated: _.get(additionalPropSchema, 'deprecated') || _.get(metaInfo, 'deprecated')
          });
        }
      });
    }
  }

  return resolvedSchemaParams;
}
Resolves schema for form params such that each individual request body param can be validated
to corresponding resolved schema params

@param {*} schema - Schema object for corresponding form params
@param {*} schemaKey - Key for corresponding Schema object to be resolved
@param {*} encodingObj - OAS Encoding object
@param {*} requestParams - collection request parameters
@param {*} metaInfo - meta information of param (i.e. required)
@param {object} components - components defined in the OAS spec. These are used to
resolve references while generating params.
@param {object} options - a standard list of options that's globally passed around. Check options.js for more.
@param {Boolean} shouldIterateChildren - Defines whether to iterate over children further for type object children
@return {Array} Resolved form schema params