createInstanceFromMap method

O? createInstanceFromMap(
  1. Map<String, Object?> map, {
  2. FieldNameResolver? fieldNameResolver,
  3. FieldValueResolver? fieldValueResolver,
})

Implementation

O? createInstanceFromMap(Map<String, Object?> map,
    {FieldNameResolver? fieldNameResolver,
    FieldValueResolver? fieldValueResolver}) {
  fieldNameResolver ??= _defaultFieldNameResolver;

  if (hasJsonConstructor) {
    if (hasJsonConstructorMandatory) {
      return createInstanceWithConstructors(jsonConstructorsMandatory, map,
          fieldNameResolver: fieldNameResolver,
          fieldValueResolver: fieldValueResolver);
    } else {
      var o = createInstanceWithConstructors(jsonConstructors, map,
          fieldNameResolver: fieldNameResolver,
          fieldValueResolver: fieldValueResolver);
      if (o != null) return o;
    }
  }

  if (hasFieldWithoutSetter || !canCreateInstanceWithoutArguments) {
    var o = createInstanceWithBestConstructor(map,
        fieldNameResolver: fieldNameResolver,
        fieldValueResolver: fieldValueResolver,
        allowOptionalOnlyConstructors: true);
    if (o != null) return o;
  } else {
    var o = createInstanceWithBestConstructor(map,
        fieldNameResolver: fieldNameResolver,
        fieldValueResolver: fieldValueResolver,
        allowEmptyConstructors: false,
        allowOptionalOnlyConstructors: true);
    if (o != null) return o;
  }

  // `class.field` to `map.key`:
  var fieldsResolved = _resolveFieldsNames(fieldNameResolver, map);

  var hasUnusedFieldInMap = fieldsResolved.length < map.length;

  // In some fields won't be used by the constructor it indicates that
  // this is not a complete constructor for the data:
  if (hasUnusedFieldInMap) {
    return null;
  }

  var fieldsNamesInMap =
      fieldsNames.where((f) => fieldsResolved.containsKey(f)).toList();

  var o = createInstance();
  if (o == null) return null;

  for (var f in fieldsNamesInMap) {
    var field = this.field(f, o)!;
    var key = fieldsResolved[f];

    if (key == null) {
      if (!field.isFinal && field.nullable) {
        field.setNullable(null);
      }
      continue;
    }

    var val = map[key];

    if (fieldValueResolver != null) {
      val = fieldValueResolver(key, val, field.type);
    }

    if (val != null) {
      if (field.isFinal) {
        throw StateError(
            "Can't create instance from `Map` due final field `$f`. $key = $val");
      }

      if (field.hasSetter) {
        field.set(val);
      }
    } else if (field.nullable) {
      if (field.hasSetter) {
        field.setNullable(null);
      }
    }
  }

  return o;
}