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 valueString = valueArg.getDisplayString(withNullability: true);
      return 'Map<String, $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);

  var mapCast = context.config.anyMap ? 'as Map' : 'as Map<String, dynamic>';

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

  String keyUsage;
  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 (context.config.anyMap &&
      keyArg.isDartCoreObject &&
      !keyArg.isNullableType) {
    keyUsage = '$_keyParam as Object';
  } else {
    keyUsage = _keyParam;
  }

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

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