decodeList method
Parses jsonString and invokes fromJson for every entry in the payload
when the input is a JSON array of objects. When nodeRoute is provided the
decoded payload must be a JSON object and its nested value is resolved by
following the segments in nodeRoute. Throws a FormatException when the
resulting payload is not a JSON array, when an entry is not a JSON object,
or when parsing fails.
Implementation
List<T> decodeList(
String? jsonString, {
List<String>? nodeRoute,
}) {
try {
if (jsonString == null || jsonString.trim().isEmpty) {
return <T>[];
}
final dynamic decoded = jsonDecode(jsonString);
if (decoded == null) {
return <T>[];
}
dynamic payload = decoded;
if (nodeRoute != null && nodeRoute.isNotEmpty) {
if (payload is! Map) {
throw const FormatException('Expected a JSON object.');
}
payload = Map<String, dynamic>.from(payload);
for (final segment in nodeRoute) {
if (payload is! Map<String, dynamic>) {
throw const FormatException('Expected a JSON object.');
}
if (!payload.containsKey(segment)) {
return <T>[];
}
final dynamic next = payload[segment];
if (next == null) {
return <T>[];
}
if (next is Map) {
payload = Map<String, dynamic>.from(next);
} else {
payload = next;
}
}
}
if (payload == null) {
return <T>[];
}
if (payload is Map) {
throw const FormatException('Expected a JSON array.');
}
if (payload is! List) {
throw const FormatException('Expected a JSON array.');
}
return List<T>.generate(payload.length, (index) {
final dynamic entry = payload[index];
if (entry is! Map<String, dynamic>) {
throw const FormatException('Expected a JSON object.');
}
final map = Map<String, dynamic>.from(entry);
return _fromJson(map);
}, growable: true);
} on FormatException catch (error) {
throw FormatException('Failed to parse JSON: ${error.message}');
} catch (error) {
throw FormatException('Failed to parse JSON: $error');
}
}