Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create objects of generic types in flutter/dart?

Tags:

json

flutter

dart

How can we create object of generic types in dart?

For my use case, each of my api responses are wrapped as ApiResponse class. For login api response, I get a json object such as

{
    "data": {
        "email": "[email protected]",
        "name": "A"
    },
    "message": "Successful",
    "status": true
}

So to parse these responses, I created classes as below, but they throw compile time error stating that The method 'fromJson' isn't defined for the class 'Type'. :

class ApiResponse<T extends BaseResponse> {
  bool status;
  String message;
  T data;

  ApiResponse.fromJson(Map<String, dynamic> json) {
    status = json['status'];
    message = json['message'];
    data = T.fromJson(json['data']);  // <<<------- here is the compile time error
  }
}

abstract class BaseResponse {
  BaseResponse.fromJson(Map<String, dynamic> json);
}

class Login extends BaseResponse {
  String name, email;

  Login.fromJson(Map<String, dynamic> json) : super.fromJson(json) {
    name = json['name'];
    email = json['email'];
  }
}

// and I want to use it like below
usage() {
  ApiResponse<Login> a = ApiResponse.fromJson({});
  String name = a.data.name;
}

Can anyone help me fix the error?

like image 484
Jainam Jhaveri Avatar asked Jan 10 '20 08:01

Jainam Jhaveri


People also ask

What are generic objects?

Generic objects are structures for storing and interacting with data in an app. They are the primary type of entity through which the engine provides access to the components of an app.

What is generic list in Dart?

In Dart, by default collections are heterogeneous. However, by the use of generics, we can make a collection to hold homogeneous values. The use of Generics makes the use of a single compulsory data type to be held inside the collection.


1 Answers

ok let's add a little hack to manage your use case:

  • let say that you have two responses Login and Error both of Type BaseResponse
abstract class BaseResponse {}

class Login extends BaseResponse {
  Login.fromJson(Map<String, dynamic> json) {}
}

class Error extends BaseResponse {
  Error.fromJson(Map<String, dynamic> json) {}
} 
  • the trick is that you will decide the type of BaseResponse at ApiResponse constructor like this
class ApiResponse<T extends BaseResponse> {
  T data;

  ApiResponse.fromJson(Map<String, dynamic> json) {
    data = _getProperDataValue<T>(json['data']);
  }

  static E _getProperDataValue<E extends BaseResponse>(
      Map<String, dynamic> jsonData) {
    switch (E) {
      case Login:
        return Login.fromJson(jsonData) as E;
      case Error:
        return Error.fromJson(jsonData) as E;
      default:
        throw UnsupportedError('Not Supported Type');
    }
  }
}
  • both responses will work
void main(List<String> arguments) {
  final loginRes = ApiResponse<Login>.fromJson(<String, dynamic>{
    'data': <String, dynamic>{},
  });
 final errorRes = ApiResponse<Error>.fromJson(<String, dynamic>{
    'data': <String, dynamic>{},
  });
}
 
like image 112
Hosam Hasan Avatar answered Sep 24 '22 20:09

Hosam Hasan