deserialize method

  1. @override
Object? 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
Object? deserialize(
  DartType targetType,
  String expression,
  TypeHelperContextWithConfig context,
  bool defaultProvided,
) {
  if (targetType is! InterfaceType) {
    return null;
  }

  final classElement = targetType.element;

  final fromJsonCtor = classElement.constructors
      .singleWhereOrNull((ce) => ce.name == 'fromJson');

  var output = expression;
  if (fromJsonCtor != null) {
    final positionalParams = fromJsonCtor.parameters
        .where((element) => element.isPositional)
        .toList();

    if (positionalParams.isEmpty) {
      throw InvalidGenerationSourceError(
        'Expecting a `fromJson` constructor with exactly one positional '
        'parameter. Found a constructor with 0 parameters.',
        element: fromJsonCtor,
      );
    }

    var asCastType = positionalParams.first.type;

    if (asCastType is InterfaceType) {
      final instantiated = _instantiate(asCastType, targetType);
      if (instantiated != null) {
        asCastType = instantiated;
      }
    }

    output = context.deserialize(asCastType, output).toString();

    final args = [
      output,
      ..._helperParams(
        context.deserialize,
        _decodeHelper,
        targetType,
        positionalParams.skip(1),
        fromJsonCtor,
      ),
    ];

    output = args.join(', ');
  } else if (_annotation(context.config, targetType)?.createFactory == true) {
    if (context.config.anyMap) {
      output += ' as Map';
    } else {
      output += ' as Map<String, dynamic>';
    }
  } else {
    return null;
  }

  // TODO: the type could be imported from a library with a prefix!
  // https://github.com/google/json_serializable.dart/issues/19
  final lambda = LambdaResult(
    output,
    '${typeToCode(targetType.promoteNonNullable())}.fromJson',
  );

  return DefaultContainer(expression, lambda);
}