deserialize method

  1. @override
String? deserialize(
  1. DartType targetType,
  2. String expression,
  3. TypeHelperContextWithConfig context,
  4. bool defaultProvided,
)
override

Returns Dart code that deserializes an expression representing a JSON literal to into targetType.

If targetType is not supported, returns null.

Let's say you want to deserialize a class Foo by taking an int stored in a JSON literal and calling the Foo.fromInt constructor.

Treating expression as a opaque Dart expression representing a JSON literal, the deserialize implementation could be a simple as:

String deserialize(DartType targetType, String expression) =>
  "new Foo.fromInt($expression)";
```.

Note that [targetType] is not used here. If you wanted to support many
types of [targetType] you could write:

```dart
String deserialize(DartType targetType, String expression) =>
  "new ${targetType.name}.fromInt($expression)";
```.

Implementation

@override
String? deserialize(
  DartType targetType,
  String expression,
  TypeHelperContextWithConfig context,
  bool defaultProvided,
) {
  if (!coreMapTypeChecker.isExactlyType(targetType)) {
    return null;
  }

  final typeArgs = targetType.typeArgumentsOf(coreMapTypeChecker)!;
  assert(typeArgs.length == 2);
  final keyArg = typeArgs.first;
  final valueArg = typeArgs.last;

  _checkSafeKeyType(expression, keyArg);

  final valueArgIsAny =
      valueArg is DynamicType ||
      (valueArg.isDartCoreObject && valueArg.isNullableType);
  final isKeyStringable = _isKeyStringable(keyArg);

  final targetTypeIsNullable = defaultProvided || targetType.isNullableType;
  final optionalQuestion = targetTypeIsNullable ? '?' : '';

  if (!isKeyStringable) {
    if (valueArgIsAny) {
      if (context.config.anyMap) {
        if (keyArg.isLikeDynamic) {
          return '$expression as Map$optionalQuestion';
        }
      } else {
        // this is the trivial case. Do a runtime cast to the known type of
        // JSON map values - `Map<String, dynamic>`
        return '$expression as Map<String, dynamic>$optionalQuestion';
      }
    }

    if (!targetTypeIsNullable &&
        (valueArgIsAny ||
            // explicitly exclude double since we need to do an explicit
            // `toDouble` on input values
            valueArg.isSimpleJsonTypeNotDouble)) {
      // No mapping of the values or null check required!
      final keyString =
          context.config.anyMap &&
              (keyArg.isDartCoreObject || keyArg is DynamicType)
          ? typeToCode(keyArg)
          : 'String';
      final valueString = typeToCode(valueArg);
      return 'Map<$keyString, $valueString>.from($expression as Map)';
    }
  }

  // In this case, we're going to create a new Map with matching reified
  // types.

  final itemSubVal = context.deserialize(valueArg, closureArg);

  final isAnyMapKey =
      context.config.anyMap ||
      keyArg.isDartCoreObject ||
      keyArg is DynamicType;
  var mapCast = isAnyMapKey ? 'as Map' : 'as Map<String, dynamic>';

  if (targetTypeIsNullable) {
    mapCast += '?';
  }

  String keyUsage;
  final customKeyConverter = const JsonConverterHelper(
    forMapKey: true,
  ).deserialize(keyArg, keyParam, context, false);
  if (customKeyConverter != null) {
    if (!isAnyMapKey &&
        customKeyConverter is LambdaResult &&
        customKeyConverter.asContent != null &&
        coreStringTypeChecker.isExactlyType(customKeyConverter.asContent!)) {
      keyUsage = '${customKeyConverter.lambda}($keyParam)';
    } else {
      keyUsage = customKeyConverter.toString();
    }
  } else if (keyArg.isEnum) {
    keyUsage = context.deserialize(keyArg, keyParam).toString();
  } else {
    if (context.config.anyMap &&
        !(keyArg.isDartCoreObject || keyArg is DynamicType)) {
      keyUsage = '$keyParam as String';
    } else if (isAnyMapKey &&
        keyArg.isDartCoreObject &&
        !keyArg.isNullableType) {
      keyUsage = '$keyParam as Object';
    } else {
      keyUsage = keyParam;
    }

    final toFromString = _forType(
      keyArg,
      dateTimeUtc: context.config.dateTimeUtc,
    );
    if (toFromString != null) {
      keyUsage = toFromString
          .deserialize(keyArg, keyUsage, false, true)
          .toString();
    }
  }

  return '($expression $mapCast)$optionalQuestion.map( '
      '($keyParam, $closureArg) => MapEntry($keyUsage, $itemSubVal),)';
}