flutter dart JsonSerializable with inherited class - flutter

I have the following two classes where one is extending from the other like this :
#JsonSerializable(nullable: true)
class Response {
final String responseCode;
final String responseMessage;
final String errorLog;
Response({this.errorLog, this.responseCode, this.responseMessage});
factory Response.fromJson(Map<String, dynamic> json) =>
_$ResponseFromJson(json);
}
.........................................................
#JsonSerializable(nullable: false)
class Verify extends Response {
Data data;
Verify({
this.data,
});
factory Verify.fromJson(Map<String, dynamic> json) => _$VerifyFromJson(json);
Map<String, dynamic> toJson() => _$VerifyToJson(this);
}
and whenever I'm trying to read response class properties from Verify class, it's always null.
so please how to achieve this?

this one I have solved by passing the parameters to super in verify class constructor like this
#JsonSerializable()
class VerifyResponse extends Response {
Data data;
VerifyResponse({
this.data,
String responseCode,
String responseMessage,
}) : super(responseCode: responseCode, responseMessage: responseMessage);
factory VerifyResponse.fromJson(Map<String, dynamic> json) =>
_$VerifyResponseFromJson(json);
Map<String, dynamic> toJson() => _$VerifyResponseToJson(this);
}
and for the response class it remains the same
#JsonSerializable()
class Response {
final String responseCode;
final String responseMessage;
Response({this.responseCode, this.responseMessage});
factory Response.fromJson(Map<String, dynamic> json) =>
_$ResponseFromJson(json);
}
it's a bit annoying but it's what it's.

You should remove 'final' keyword from Response Class
#JsonSerializable(nullable: true)
class Response {
String responseCode;
String responseMessage;
String errorLog;
Response({this.errorLog, this.responseCode, this.responseMessage});
factory Response.fromJson(Map<String, dynamic> json) =>
_$ResponseFromJson(json);
}

It worked by adding super(); explicitly to the child class's constructor.
#JsonSerializable()
class VerifyResponse extends Response {
Data data;
VerifyResponse({
this.data,
String responseCode,
String responseMessage,
//No need to list all parent class properties
}) : super();
factory VerifyResponse.fromJson(Map<String, dynamic> json) =>
_$VerifyResponseFromJson(json);
Map<String, dynamic> toJson() => _$VerifyResponseToJson(this);
}

Related

Flutter Unhandled Exception: type 'Null' is not a subtype of type 'Response<AuthResponse>' in type cast

I can't seem to figure out the issue in my flutter GetConnect request, I am using the Getx's Getconnect library to send an API request to authenticate users, the requests are authenticated successfully but then the app throws an error when I try to get the user data and token back,
class AuthService {
final IHttpConnect _connect;
const AuthService(IHttpConnect connect) : _connect = connect;
String get _prefix => 'auth';
Future<AuthResponse> authenticateUser(
var body,
) async {
final response = await _connect.post(
'$_prefix/login',
body,
decoder: (value){
print(value);
AuthResponse data = AuthResponse.fromJson(
value as Map<String, dynamic>,
);
return data;
},
);
if (response.success) {
return response.payload!;
} else {
switch (response.statusCode) {
case 404:
throw UserNotFoundException();
default:
throw DefaultException(message: response.payload!.error!);
}
}
}
}
My AuthResponse model looks like this
import 'package:json_annotation/json_annotation.dart';
part 'auth_response.g.dart';
#JsonSerializable()
class AuthResponse {
AuthResponse({
required this.success,
this.data,
this.error,
});
final bool success;
final Data? data;
final String? error;
factory AuthResponse.fromJson(Map<String, dynamic> json) => _$AuthResponseFromJson(json);
Map<String, dynamic> toJson() => _$AuthResponseToJson(this);
}
#JsonSerializable()
class Data {
Data({
required this.token,
required this.user,
});
final String token;
final User user;
factory Data.fromJson(Map<String, dynamic> json) => _$DataFromJson(json);
Map<String, dynamic> toJson() => _$DataToJson(this);
}
#JsonSerializable()
class User {
User({
required this.id,
required this.name,
required this.email,
required this.emailVerifiedAt,
required this.createdAt,
required this.updatedAt,
});
final int id;
final String name;
final String email;
#JsonKey(name: 'email_verified_at')
final DateTime? emailVerifiedAt;
#JsonKey(name: 'created_at')
final DateTime createdAt;
#JsonKey(name: 'updated_at')
final DateTime updatedAt;
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}
If I print the data I get
{success: true, data: {token: 157|4YXMdrMwDIECxsVSf5hIeON5scCu9lZTQP2B5wXa, user: {id: 1, name: Kenya Friesen, email: mdavis#yahoo.com, email_verified_at: 2022-11-18T00:27:42.000000Z, created_at: 2022-11-18T00:27:42.000000Z, updated_at: 2022-11-18T00:27:42.000000Z}}, error: ddd}
IHttpConnect class
import './response.model.dart';
abstract class IHttpConnect {
Future<Response<T>> get<T>(
String url, {
required T Function(dynamic)? decoder,
});
Future<Response<T>> post<T>(
String url,
Map<String, dynamic> body, {
T Function(dynamic)? decoder,
});
Future<Response<T>> put<T>(
String url,
Map<String, dynamic> body, {
T Function(dynamic)? decoder,
});
Future<Response<T>> patch<T>(
String url,
Map<String, dynamic> body, {
T Function(dynamic)? decoder,
});
Future<Response<T>> delete<T>(
String url, {
required T Function(dynamic)? decoder,
});
}
Response Class
class Response<T> {
final int statusCode;
final T? payload;
bool get success => statusCode <= 200;
const Response({
required this.statusCode,
required this.payload,
});
}
I appreciate any assistance

flutter map was called on a null value

I try to get data from api. CallListDto class is empty according to user type. So, sometime this class is empty sometimes it has data. I populate dropdown menu items with this class.
My problem is, when this class is empty i got error. How can i solve this.
My model class is below
Login loginFromJson(String str) => Login.fromJson(json.decode(str));
String loginToJson(Login data) => json.encode(data.toJson());
class Login {
Login({
required this.token,
required this.callListDto,
});
String token;
List<CallListDto> callListDto;
factory Login.fromJson(Map<String, dynamic> json) => Login(
token: json["token"],
callListDto: List<CallListDto>.from(
json["callListDto"].map((x) => CallListDto.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"token": token,
"callListDto": List<dynamic>.from(callListDto.map((x) => x.toJson())),
};
}
class CallListDto {
CallListDto({
required this.callId,
required this.stationCode,
required this.callType,
});
int callId;
String stationCode;
int callType;
factory CallListDto.fromJson(Map<String, dynamic> json) => CallListDto(
callId: json["callID"],
stationCode: json["stationCode"],
callType: json["callType"],
);
Map<String, dynamic> toJson() => {
"callID": callId,
"stationCode": stationCode,
"callType": callType,
};
}
Before calling the model class check that str is not empty, for example
if (dataObject.isEmpty) return;

How to do a toJson encode method on Dart/Flutter?

I used the fromJson method to recover a Struct with a List from Json decode http request and receiver it on my class, but now i want to do a reverse, i want to pass the data on my class to my toJson method and send him to a Json encode http POST. Please, i new on Dart/Flutter, someone know how to do this?
import 'dart:convert';
List<Itens> userFromJson(String str) =>
List<Itens>.from(jsonDecode(str).map((x) => Itens.fromJson(x)));
class Coletas {
final int codigo;
final String dataIni;
late String? dataFin;
late String? status;
final List<Itens> itemList;
Coletas(
{
required this.dataIni,
this.dataFin,
this.status,
required this.codigo,
required this.itemList
}
);
factory Coletas.fromJson(Map<String, dynamic> json) {
return Coletas(
dataIni: json['dtData'],
codigo: json['iCodigo'],
itemList: List<Itens>.from(json['stItens'].map((x) => Itens.fromJson(x))),
);
}
Map<String, dynamic> toMap() {
return {
'codigo': codigo,
'dataIni': dataIni,
'dataFin': dataFin,
'status': status
};
}
}
class Itens {
final int? id;
final int codigo;
late int quantidade;
late String? status;
final String codigoEAN;
Itens({
this.id,
this.status,
required this.codigo,
required this.codigoEAN,
required this.quantidade,
});
Map<String, dynamic> toJson(){
return {
'icodigo' : codigo,
'sCodigoBarras': codigoEAN,
'iQtd': quantidade
};
}
factory Itens.fromJson(Map<String, dynamic> json) {
return Itens(
codigo: json['iCodigo'],
codigoEAN: json['sCodigoBarras'],
quantidade: json['iQtd'],
);
}
Map<String, dynamic> toMap() {
return {
'id': id,
'status': status,
'codigo': codigo,
'codigoEAN': codigoEAN,
'quantidade': quantidade,
};
}
}
I tried to pass ever item on List separeted so, but not happen i expected.
Map<String, dynamic> toJSon(Coletas value) =>
{
'dtData' : dataIni,
'iCodigo': codigo,
'stItens': [],
};
For a better structure - format and use you can look at the flutter serialization documentation : https://docs.flutter.dev/development/data-and-backend/json.
It explains how to create your model and how to generate them to create fromJson and toJson Model based on the defined data. (https://docs.flutter.dev/development/data-and-backend/json#creating-model-classes-the-json_serializable-way)
It will helps you with your parsing - sending - receiving data.
I think you should assign Coletas as
Map<String, dynamic> toJSon(Coletas value) =>
{
'dtData' : value.dataIni,
'iCodigo': value.codigo,
'stItens': value.itemList,
};

Flutter deserialization of inherited classes with json_serializable

I have problem trying deserialise inherited class with json_serializable package in Dart/Flutter. Here is the code example:
#JsonSerializable(explicitToJson: true)
class Document {
String id = UniqueKey().toString();
String name='';
List<Component> components=[]; //list of Components
Document({required this.components}):super();
Document.empty();
factory Document.fromJson(Map<String, dynamic> json) =>_$DocumentFromJson(json);
Map<String, dynamic> toJson() => _$DocumentToJson(this);
}
#JsonSerializable()
class Component { //Component Base Class
String id = UniqueKey().toString();
String name='';
Component();
factory Component.fromJson(Map<String, dynamic> json) =>_$ComponentFromJson(json);
Map<String, dynamic> toJson() => _$ComponentToJson(this);
}
#JsonSerializable()
class TextComponent extends Component{ //inherited from Component
String text='';
TextComponent():super();
TextComponent.text({required this.text}):super();
factory TextComponent.fromJson(Map<String, dynamic> json) =>_$TextComponentFromJson(json);
#override Map<String, dynamic> toJson() => _$TextComponentToJson(this);
}
And here is the test:
void main() {
//creating json from object
Document d = Document(components:[TextComponent.text(text: 'text')] );
print(d.components[0].runtimeType); //-type is : TextComponent
var json = d.toJson();
//create object from json
var newDoc = Document.fromJson(json);
print(newDoc.components[0].runtimeType); //-type is : Component which is the base class
}
After deserialising the inherited class is downcasted to base class, but i need the inherited class.
Ok, I found this package which does everything:
https://pub.dev/packages/dart_mappable#custom-mappers

How to exclude a single field from json serialization with json_serializable?

I use https://pub.dev/packages/json_serializable to generate Json serialization for my classes. This works fine. Now I would like to ignore a single field only for the json generation but not when reading a json e.g. the dateOfBirth in following example:
#JsonSerializable()
class Person {
final String firstName;
final String lastName;
final DateTime dateOfBirth; //<-- ignore this field for json serialization but not for deserialization
Person({this.firstName, this.lastName, this.dateOfBirth});
factory Person.fromJson(Map<String, dynamic> json) => _$PersonFromJson(json);
Map<String, dynamic> toJson() => _$PersonToJson(this);
}
When I use JsonKey.ignore the field is ignored for toJson and fromJson.
Is there a JsonKey Annotation for this case that I am missing?
Here's a workaround I've been using so I don't end up storing documentID's twice in my FB database while still having them available on the objects:
#JsonSerializable()
class Exercise {
const Exercise({
#required this.documentID,
// ...
}) : assert(documentID != null);
static toNull(_) => null;
#JsonKey(toJson: toNull, includeIfNull: false)
final String documentID;
//...
factory Exercise.fromJson(Map<String, dynamic> json) =>
_$ExerciseFromJson(json);
Map<String, dynamic> toJson() => _$ExerciseToJson(this);
}
where toNull is just
toNull(_) => null;
The toJson will null the value and then the includeIfNull won't serialize the value.
With null safety it can be:
#JsonKey(ignore: true)
final String documentID;