Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic class in Flutter

Tags:

flutter

dart

I have a common response structure from http request like this

class CommonResponse<T> {
  int total;
  List<T> data;
  bool success;

  CommonResponse({this.total, this.data, this.success});

  CommonResponse.fromJson(Map<String, dynamic> json) {
    total = json['total'];
    data = json['data'];

    success = json['success'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['total'] = this.total;
    data['data'] = this.data;
    data['success'] = this.success;
  }
}

Now I need to parse the generic data. For example I am getting list of zones inside data object in CommonResponse

class Zone {
  bool active;
  String id;
  String name;

  Zone({this.active, this.id, this.name});

  Zone.fromJson(Map<String, dynamic> json) {
    this.active = json['active'];
    this.id = json['id'];
    this.name = json['name'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['active'] = this.active;
    data['id'] = this.id;
    data['name'] = this.name;
  }
}

How to get list of zones?

  var response = {
    "data": [
      {
        "active": true,
        "created_on": "2020-03-12T09:56:11+00:00",
        "description": "For Testing",
        "id": "b17627eb-8a39-4230-80fe-ebed77f7e0e2",
        "name": "Office",
        "updated_on": "2020-03-19T12:26:16+00:00"
      }
    ],
    "success": true,
    "total": 1
  };
  CommonResponse<Zone> common = CommonResponse.fromJson(response);
  print(common.data);

This is what i tried. I am getting perfect response but am getting error getting list of Zone. Error is cannot convert List<dynamic> to Zone.

like image 617
Lakshya Punhani Avatar asked Dec 08 '22 10:12

Lakshya Punhani


1 Answers

To generate proper transformation from and to json you can use json_serializable package. It supports generic arguments via @JsonSerializable(genericArgumentFactories: true).

First of all let's do small code refactor:

Move Zone class into zone.dart:

import 'package:json_annotation/json_annotation.dart';

part 'zone.g.dart';

@JsonSerializable()
class Zone {
  bool active;
  String id;
  String name;

  Zone({this.active, this.id, this.name});

  factory Zone.fromJson(Map<String, dynamic> json) => _$ZoneFromJson(json);
  Map<String, dynamic> toJson() => _$ZoneToJson(this);
}

CommonResponse class to common_response.dart

import 'package:json_annotation/json_annotation.dart';

part 'common_response.g.dart';

@JsonSerializable(genericArgumentFactories: true)
class CommonResponse<T> {
  int total;
  List<T> data;
  bool success;

  CommonResponse({this.total, this.data, this.success});

  factory CommonResponse.fromJson(
    Map<String, dynamic> json,
    T Function(Object json) fromJsonT,
  ) =>
      _$CommonResponseFromJson(json, fromJsonT);
  Map<String, dynamic> toJson(Object Function(T value) toJsonT) =>
      _$CommonResponseToJson(this, toJsonT);
}

And run flutter pub run build_runner build.

The output is as below:

zone.g.dart

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'zone.dart';

// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************

Zone _$ZoneFromJson(Map<String, dynamic> json) {
  return Zone(
    active: json['active'] as bool,
    id: json['id'] as String,
    name: json['name'] as String,
  );
}

Map<String, dynamic> _$ZoneToJson(Zone instance) => <String, dynamic>{
      'active': instance.active,
      'id': instance.id,
      'name': instance.name,
    };

common_response.g.dart

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'common_response.dart';

// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************

CommonResponse<T> _$CommonResponseFromJson<T>(
  Map<String, dynamic> json,
  T Function(Object json) fromJsonT,
) {
  return CommonResponse<T>(
    total: json['total'] as int,
    data: (json['data'] as List)?.map(fromJsonT)?.toList(),
    success: json['success'] as bool,
  );
}

Map<String, dynamic> _$CommonResponseToJson<T>(
  CommonResponse<T> instance,
  Object Function(T value) toJsonT,
) =>
    <String, dynamic>{
      'total': instance.total,
      'data': instance.data?.map(toJsonT)?.toList(),
      'success': instance.success,
    };

Sample usage:

import 'common_response.dart';
import 'zone.dart';

void main() {
  var response = {
    'data': [
      {
        'active': true,
        'created_on': '2020-03-12T09:56:11+00:00',
        'description': 'For Testing',
        'id': 'b17627eb-8a39-4230-80fe-ebed77f7e0e2',
        'name': 'Office',
        'updated_on': '2020-03-19T12:26:16+00:00'
      }
    ],
    'success': true,
    'total': 1
  };
  var common =
      CommonResponse<Zone>.fromJson(response, (data) => Zone.fromJson(data));

  for (var zone in common.data) {
    print(zone.id);
  }
}

like image 120
Owczar Avatar answered Dec 22 '22 00:12

Owczar