Having trouble creating generic Dart constructor for Json conversion

Issue

To all Dart gurus: I’m trying to implement a generic networking layer in Dart that converts REST service response to a specified model class:

// The idea is to make a network call and get a deserialized model as a response:

final token =
        await _authNetworkService.execute<AccessTokenResponse>(request);

Here is the implementation:

// Model interface
abstract class JsonConvertible {
  Map<String, dynamic> toJson();
  JsonConvertible.fromJson(Map<String, dynamic> json);
}

// Model
class AccessTokenResponse extends JsonConvertible {
  String? accessToken;

  @override
  Map<String, dynamic> toJson() {
    return {};
  }

  @override
  AccessTokenResponse.fromJson(Map<String, dynamic> json)
      : super.fromJson(json) {
    accessToken = json['access_token'];
  }
}

// Network response class
class NetworkResponse<Model> {
  Model data;
  
  NetworkResponse.ok(this.data);
}

// Class to create a valid network service request
class NetworkRequest {
}

// Class that performs all network calls
class NetworkService {
  Future<NetworkResponse<M>> execute<M extends JsonConvertible>(NetworkRequest request) async {
    // For simplicity replaced all DIO calls with static data:
    final response = {'data': {'access_token': 'XXX'}};

    return NetworkResponse.ok(M.fromJson(response['data'])); //<- Fails here with error: Method 'fromJson' isn't defined for the type 'Type'...
  }
}

DartPad: https://dartpad.dev/?id=9a29a7e49a084e69fd1d8078d5f2b977

How can I achieve expected behavior?

Solution

one way you can solve this is by passing the fromJson constructor as an argument to the execute function but this will add another step for every time execute is called

// Class that performs all network calls
class NetworkService {
  Future<NetworkResponse<M>> execute<M extends JsonConvertible>(NetworkRequest request,M Function(Map<String, dynamic>) parser ) async {
    // For simplicity replaced all DIO calls with static data:
    final response = {'data': {'access_token': 'XXX'}};

    return NetworkResponse.ok( parser(response['data']!)); //<- Fails here with error: Method 'fromJson' isn't defined for the type 'Type'...
  }
}

and this is how you would call the execute function

 final token =
        await _authNetworkService.execute<AccessTokenResponse>(request,AccessTokenResponse.fromJson);

Answered By – Elias Teeny

Answer Checked By – Mildred Charles (FlutterFixes Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *