skip to Main Content

I have an async function that gets some data from SQL server. The error points to the last line of this function. I am using an await when I call this function in another file. Why am I getting this error? I need to end up with a List<Map<String, String>> to use in another file. I already tried doing res = json.decode(res) as List<Map<String, String>>; but this didn’t work.

Future<List<Map<String, String>>> getServerList() async {
  //...

  //res is a String here
  //example of data inside res variable: [{ServerName: Server1, ServerIP: IP1, DatabaseName: DB1, PortNum: 1433, Status: null}, {ServerName: Server2, ServerIP: IP2, DatabaseName: DB2, PortNum: 1433, Status: null}]
  var res = await SqlConn.readData("declare @Status nvarchar(4000) exec spHandheldServerList @Status output"); 

  //...     

  //Changes res from a String to a List<dynamic>
  res = json.decode(res);

  return res; //ERROR POINTS HERE
}

2

Answers


  1. Remove the ‘Future’ from
    Future<List<Map<String, String>>> getServerList() async to return the list you need of type List<Map<String, String>>.
    Basically your variable stops being of type ‘Future’ when you resolve it with the await and convert it to json (which already returns the list of type List<Map<String, String>>)

    Login or Signup to reply.
  2. When json.decode parses JSON, the runtime type of the returned value is going to be one of the following depending on the JSON string that was parsed:

    • null
    • bool
    • int
    • double
    • String
    • List<dynamic>
    • Map<String, dynamic>

    (In the last two cases, every item in the list or map will also be one of these types.)

    In your case, it is List<dynamic>, which is not implicitly convertible to any other kind of list. You need to call either cast or map (or both) in order to explicitly convert the list to the type you need. And because you’re dealing with Maps that’s nested within a List, not only do you need to convert the outer List, you also need to convert the inner Maps.

    final res = await SqlConn.readData(...);
    
    final dynlist = json.decode(str) as List<dynamic>;
    
    final listOfMaps = dynlist.map((ch) => (ch as Map<String, dynamic>).cast<String, String>());
    
    return listOfMaps;
    

    If the structure of the JSON is known beforehand, you want to be parsing any Map you have into a data class. This gives you type safety and reliability that are impossible to have from maps alone.

    class ServerMetadata {
      final String serverName;
      final String serverIP;
      final String databaseName;
      final int portNum;
      final String? status;
      
      const ServerMetadata(this.serverName, this.serverIP, this.databaseName, this.portNum, this.status);
      
      factory ServerMetadata.fromJson(Map<String, dynamic> map) {
        return ServerMetadata(
          map['ServerName'] as String,
          map['ServerIP'] as String,
          map['DatabaseName'] as String,
          map['PortNum'] as int,
          map['Status'] as String?,
        );
      }
    }
    
    final res = await SqlConn.readData(...);
    final dynlist = json.decode(str) as List<dynamic>;
    final servers = dynlist.map((map) => ServerMetadata.fromJson(map));
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search