schultek / dart_mappable

Improved json serialization and data classes with full support for generics, inheritance, customization and more.
https://pub.dev/packages/dart_mappable
MIT License
135 stars 20 forks source link

Cause `UnresolvedType` is not a subtype of type `T(Generic)` in type cast error #166

Closed UkiDelly closed 4 months ago

UkiDelly commented 4 months ago

I was trying to use generic to decode the json into a different model depending on the data I received from the network communication. The problem is when it try to decode from json (either string and map), it cause an error of

UnresolvedType is not a subtype of T(Generic type) in type cast

How could I solve this problem?

This is the BaseResponse model that I use to convert the response from the network.

@MappableClass()
final class BaseResponse<T> with BaseResponseMappable {
  const BaseResponse({
    this.success,
    this.error,
  });

  final SuccessModel? success;
  final ErrorModel? error;

  factory BaseResponse.fromJson(Map<String, dynamic> map) => BaseResponseMapper.fromMap(map);

  factory BaseResponse.fromJsonString(String json) => BaseResponseMapper.fromJson(json);
}

And also SuccessModel is using generic too

@MappableClass()
final class SuccessModel<T> with SuccessModelMappable {
  const SuccessModel({
    required this.data,
    required this.resultCode,
    required this.resultMessage,
  });

  final T? data;
  final int resultCode;
  final String resultMessage;

  factory SuccessModel.fromJson(Map<String, dynamic> map) => SuccessModelMapper.fromMap(map);
  factory SuccessModel.fromJsonString(String json) => SuccessModelMapper.fromJson(json);
}

I am using this TermModel to test it

@MappableClass()
final class TermModel with TermModelMappable {
  const TermModel({
    required this.agid,
    this.deleted,
    this.lid,
    required this.name,
    this.cid,
    this.cidName,
    this.content,
    this.sortNo,
    this.required,
    this.requiredName,
    this.modate,
    this.regdate,
    this.isChecked = false,
  });
  final int agid;
  final int? deleted;
  final int? lid;
  final String name;
  final int? cid;
  final String? cidName;
  final String? content;
  final int? sortNo;
  final int? required;
  final String? requiredName;
  final String? modate;
  final String? regdate;
  final bool isChecked;

  factory TermModel.fromJson(Map<String, dynamic> map) => TermModelMapper.fromMap(map);
  factory TermModel.fromJsonString(String json) => TermModelMapper.fromJson(json);
}

This is the code I test

import 'dart:convert';
import 'package:http/http.dart' hide BaseResponse;

Future<void> main(List<String> arguments) async {
  final response = await get(Uri.parse("my server api"));

  // decode to Map
  final encodeBody = jsonDecode(response.body);

  print(encodeBody);
  final res = BaseResponse<List<TermModel>>.fromJson(encodeBody);
  print(res.success);
}

Then this is the output

screenshot_2024 02 08_01-17_PM

schultek commented 4 months ago

Any class used through a generic type must be initialized beforehand.

Do TermModelMapper.ensureInitialized()

UkiDelly commented 4 months ago

In this situation, there is only one TermModelMapper, but if there are more models used as generics, will there be no choice but to hardcode .ensureInitialized() of all models?

schultek commented 4 months ago

Check out https://pub.dev/documentation/dart_mappable/latest/topics/Generics-topic.html#generated-initializer

Unfortunately this can't be done fully automatically since Dart does not have static initialization of classes.