deserialize method
Object?
deserialize(
- DartType targetType,
- String expression,
- TypeHelperContextWithConfig context,
- 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;
var fromJsonCtor = classElement.constructors
.where((ce) => ce.name == 'fromJson')
.singleOrNull;
var output = expression;
if (fromJsonCtor != null) {
while (fromJsonCtor!.enclosingElement is ClassElement &&
(fromJsonCtor.enclosingElement as ClassElement).isMixinApplication &&
fromJsonCtor.superConstructor != null) {
fromJsonCtor = fromJsonCtor.superConstructor!.baseElement;
}
final positionalParams = fromJsonCtor.formalParameters
.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,
);
}
final instantiatedTarget =
targetType.asInstanceOf(fromJsonCtor.enclosingElement) ?? targetType;
final instantiatedCtor = instantiatedTarget.constructors
.where((ce) => ce.baseElement == fromJsonCtor!.baseElement)
.singleOrNull;
final instantiatedPositionalParams = instantiatedCtor?.formalParameters
.where((element) => element.isPositional)
.toList();
final asCastType =
instantiatedPositionalParams != null &&
instantiatedPositionalParams.isNotEmpty
? instantiatedPositionalParams.first.type
: positionalParams.first.type;
output = context.deserialize(asCastType, output).toString();
final args = [
output,
..._helperParams(
context.deserialize,
_decodeHelper,
targetType,
positionalParams.skip(1).where((e) => e.isRequiredPositional),
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);
}