generateFromMapMethod method
void
generateFromMapMethod(
- ClassBuilder clazz,
- BuildContext ctx,
- LibraryBuilder file
)
Implementation
void generateFromMapMethod(
ClassBuilder clazz, BuildContext ctx, LibraryBuilder file) {
clazz.methods.add(Method((method) {
method
..static = true
..name = 'fromMap'
..returns = ctx.modelClassType
..requiredParameters.add(
Parameter((b) => b
..name = 'map'
..type = Reference('Map')),
);
// Add all `super` params
if (ctx.constructorParameters.isNotEmpty) {
for (var param in ctx.constructorParameters) {
method.requiredParameters.add(Parameter((b) => b
..name = param.name
..type = convertTypeReference(param.type)));
}
}
var buf = StringBuffer();
// Required Fields
ctx.requiredFields.forEach((key, msg) {
if (ctx.excluded[key]?.canDeserialize == false) return;
var name = ctx.resolveFieldName(key);
if (msg.contains("'")) {
buf.writeln('''
if (map['$name'] == null) {
throw FormatException("$msg");
}
''');
} else {
buf.writeln('''
if (map['$name'] == null) {
throw FormatException('$msg');
}
''');
}
});
buf.writeln('return ${ctx.modelClassName}(');
var i = 0;
// Parameters in the constructor
for (var param in ctx.constructorParameters) {
if (i++ > 0) buf.write(', ');
buf.write(param.name);
}
// Fields
for (var field in ctx.fields) {
var type = ctx.resolveSerializedFieldType(field.name);
if (ctx.excluded[field.name]?.canDeserialize == false) continue;
var alias = ctx.resolveFieldName(field.name);
if (i++ > 0) buf.write(', ');
var deserializedRepresentation =
"map['$alias'] as ${typeToString(type)}";
if (type.nullabilitySuffix == NullabilitySuffix.question) {
deserializedRepresentation += '?';
}
var defaultValue = 'null';
var existingDefault = ctx.defaults[field.name];
if (existingDefault != null) {
var d = dartObjectToString(existingDefault);
if (d != null) {
defaultValue = d;
if (!deserializedRepresentation.endsWith("?")) {
deserializedRepresentation += "?";
}
}
deserializedRepresentation =
'$deserializedRepresentation ?? $defaultValue';
}
var fieldNameDeserializer = ctx.fieldInfo[field.name]?.deserializer;
if (fieldNameDeserializer != null) {
var name = MirrorSystem.getName(fieldNameDeserializer);
deserializedRepresentation = "$name(map['$alias'])";
} else if (dateTimeTypeChecker.isAssignableFromType(type)) {
if (field.type.nullabilitySuffix != NullabilitySuffix.question) {
if (defaultValue.toLowerCase() == 'null') {
defaultValue = 'DateTime.parse("1970-01-01 00:00:00")';
} else {
defaultValue = 'DateTime.parse("$defaultValue")';
}
}
deserializedRepresentation = "map['$alias'] != null ? "
"(map['$alias'] is DateTime ? (map['$alias'] as DateTime) : DateTime.parse(map['$alias'].toString()))"
' : $defaultValue';
}
// Serialize model classes via `XSerializer.toMap`
else if (isModelClass(type)) {
var rc = ReCase(type.getDisplayString(withNullability: true));
deserializedRepresentation = "map['$alias'] != null"
" ? ${rc.pascalCase.replaceAll('?', '')}Serializer.fromMap(map['$alias'] as Map)"
' : $defaultValue';
} else if (type is InterfaceType) {
if (isListOfModelType(type)) {
if (defaultValue == 'null') {
defaultValue = '[]';
}
var rc = ReCase(
type.typeArguments[0].getDisplayString(withNullability: true));
deserializedRepresentation = "map['$alias'] is Iterable"
" ? List.unmodifiable(((map['$alias'] as Iterable)"
'.whereType<Map>())'
'.map(${rc.pascalCase.replaceAll('?', '')}Serializer.fromMap))'
' : $defaultValue';
} else if (isMapToModelType(type)) {
// TODO: This requires refractoring
if (defaultValue == 'null') {
defaultValue = '{}';
}
var rc = ReCase(
type.typeArguments[1].getDisplayString(withNullability: true));
deserializedRepresentation = '''
map['$alias'] is Map
? Map.unmodifiable((map['$alias'] as Map).keys.fold({}, (out, key) {
return out..[key] = ${rc.pascalCase.replaceAll('?', '')}Serializer
.fromMap(((map['$alias'] as Map)[key]) as Map);
}))
: $defaultValue
''';
} else if (type.element is Enum) {
deserializedRepresentation = '''
map['$alias'] is ${type.getDisplayString(withNullability: true)}
? (map['$alias'] as ${type.getDisplayString(withNullability: true)}) ?? $defaultValue
:
(
map['$alias'] is int
? ${type.getDisplayString(withNullability: true)}.values[map['$alias'] as int]
: $defaultValue
)
''';
//log.warning('Code => $deserializedRepresentation');
} else if (const TypeChecker.fromRuntime(List)
.isAssignableFromType(type) &&
type.typeArguments.length == 1) {
if (defaultValue == 'null') {
defaultValue = '[]';
}
var arg = convertTypeReference(type.typeArguments[0])
.accept(DartEmitter(useNullSafetySyntax: true));
deserializedRepresentation = '''
map['$alias'] is Iterable
? (map['$alias'] as Iterable).cast<$arg>().toList()
: $defaultValue
''';
} else if (const TypeChecker.fromRuntime(Map)
.isAssignableFromType(type) &&
type.typeArguments.length == 2) {
var key = convertTypeReference(type.typeArguments[0])
.accept(DartEmitter(useNullSafetySyntax: true));
var value = convertTypeReference(type.typeArguments[1])
.accept(DartEmitter(useNullSafetySyntax: true));
if (defaultValue == 'null') {
defaultValue = '{}';
}
deserializedRepresentation = '''
map['$alias'] is Map
? (map['$alias'] as Map).cast<$key, $value>()
: $defaultValue
''';
} else if (const TypeChecker.fromRuntime(Uint8List)
.isAssignableFromType(type)) {
deserializedRepresentation = '''
map['$alias'] is Uint8List
? (map['$alias'] as Uint8List)
:
(
map['$alias'] is Iterable<int>
? Uint8List.fromList((map['$alias'] as Iterable<int>).toList())
:
(
map['$alias'] is String
? Uint8List.fromList(base64.decode(map['$alias'] as String))
: $defaultValue
)
)
''';
}
}
buf.write('${field.name}: $deserializedRepresentation');
}
buf.write(');');
method.body = Code(buf.toString());
}));
}