Skip to content

IMap: _TypeError (type 'String' is not a subtype of type 'num / bool / int' in type cast) #1332

Closed
@JoanSchi

Description

@JoanSchi

Hi,

If json_serializable is used with IMap a Type error occurs when string is converted in the into bool / int/ double (num) or duration (FromJson). However DateTime, BigInt or Uri for example are parsed as expected.

json_serializable: ^6.7.0
fast_immutable_collections: ^9.1.5

FromJson
Looking to the generated code some types are not parsed correctly with the function FromJson:

Type error
IMap<X, String>.fromJson
X = int: (value) => value as bool,
X = bool: (value) => value as bool,
X double: (value) => (value as num).toDouble(),

Works good
IMap<X, String>.fromJson
X: (value) => DateTime.parse(value as String),
X: (value) => BigInt.parse(value as String),

ToJson
I do not known if it is necessary, but not everything is converted to string:

Not converted to string (problem?):
double/int/bool: (value) => value (Should this not be a String?)

Converted to string (works good)
DateTime: (value) => value.toIso8601String()
BigInt: (value) => value.toString(),

If this is resolved, I can resolve marcglasberg/fast_immutable_collections#58.

Thank you.

Example

import 'package:fast_immutable_collections/fast_immutable_collections.dart';
import 'package:imap_test/example.dart';



void main() {
 
  final SerializableExample serializable = SerializableExample(

      // Works as espected:

      iMap: {DateTime(2023, 6, 25): 'IMap<DateTime,String>'}.lock,
      iEnumMap: {TestEnum.testValue: 'IMap<Enum,String>'}.lock,
      iStringMap: {'stringKey': 'IMap<String,String>'}.lock,
      iBigIntMap: {BigInt.from(8) : 'IMap<BigInt,String>'}.lock,
      
      iUriMap: {Uri(
    scheme: 'https',
    host: 'dart.dev',
    path: '/guides/libraries/library-tour',
    fragment: 'numbers') : 'Imap wit uri'}.lock,
      
      // Bug value as Type -> error

      // iDoubleMap :  {5.5: 'IMap<double,String>'}.lock,
      // iDurationMap: {Duration(milliseconds:200): 'IMap<Duration,String>'}.lock,
      // iIntMap: {2: 'IMap<Int,String>'}.lock,
      // iboolMap: {true : 'IMap<bool,String>'}.lock,
      );

  final Map<String, dynamic> json = serializable.toJson();

  final fromJsonTestMap = SerializableExample.fromJson(json);

  print('Output test serializableExample:\n ${fromJsonTestMap.toString()}');

}

SerializableExample


import 'package:fast_immutable_collections/fast_immutable_collections.dart';
import 'package:freezed_annotation/freezed_annotation.dart';

part 'example.g.dart';

enum TestEnum {
  testValue,
}

//  BigInt, bool, DateTime, double, Duration, Enum, int, Iterable, List, Map, num, Object, Record, Set, String, Uri
@JsonSerializable()
class SerializableExample {
  /// The generated code assumes these values exist in JSON.
  final IMap<DateTime, String> iMap;
  final IMap<TestEnum, String> iEnumMap;
  final IMap<String, String> iStringMap;
  final IMap<BigInt, String> iBigIntMap;
  final IMap<bool, String> iboolMap;
  final IMap<int, String> iIntMap;
  final IMap<Duration, String> iDurationMap;
  final IMap<double, String> iDoubleMap;
  final IMap<Object, String> iObjectMap;
final IMap<Uri, String> iUriMap;
  final Map<int, String> intMap;


  SerializableExample({
     this.iMap = const IMapConst({}),
     this.iEnumMap= const IMapConst({}),
     this.iStringMap = const IMapConst({}),
     this.iBigIntMap = const IMapConst({}),
     this.iboolMap = const IMapConst({}),
     this.iIntMap = const IMapConst({}),
    this.iDurationMap = const IMapConst({}),
     this.iDoubleMap = const IMapConst({}),
     this.iObjectMap = const IMapConst({}),
     this.iUriMap = const IMapConst({}),
     this.intMap = const{}
  });

  /// Connect the generated [_$PersonFromJson] function to the `fromJson`
  /// factory.
  factory SerializableExample.fromJson(Map<String, dynamic> json) =>
      _$SerializableExampleFromJson(json);

  /// Connect the generated [_$PersonToJson] function to the `toJson` method.
  Map<String, dynamic> toJson() => _$SerializableExampleToJson(this);
 

  @override
  String toString() {
    return 'SerializableExample(iMap: $iMap, iEnumMap: $iEnumMap, iStringMap: $iStringMap, iBigIntMap: $iBigIntMap, iboolMap: $iboolMap, iIntMap: $iIntMap, iDurationMap: $iDurationMap, iDoubleMap: $iDoubleMap, iObjectMap: $iObjectMap, iUriMap: $iUriMap, intMap: $intMap)';
  }
}

Generator code

part of 'example.dart';

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

SerializableExample _$SerializableExampleFromJson(Map<String, dynamic> json) =>
    SerializableExample(
      iMap: json['iMap'] == null
          ? const IMapConst({})
          : IMap<DateTime, String>.fromJson(
              json['iMap'] as Map<String, dynamic>,
              (value) => DateTime.parse(value as String),
              (value) => value as String),
      iEnumMap: json['iEnumMap'] == null
          ? const IMapConst({})
          : IMap<TestEnum, String>.fromJson(
              json['iEnumMap'] as Map<String, dynamic>,
              (value) => $enumDecode(_$TestEnumEnumMap, value),
              (value) => value as String),
      iStringMap: json['iStringMap'] == null
          ? const IMapConst({})
          : IMap<String, String>.fromJson(
              json['iStringMap'] as Map<String, dynamic>,
              (value) => value as String,
              (value) => value as String),
      iBigIntMap: json['iBigIntMap'] == null
          ? const IMapConst({})
          : IMap<BigInt, String>.fromJson(
              json['iBigIntMap'] as Map<String, dynamic>,
              (value) => BigInt.parse(value as String),
              (value) => value as String),
      iboolMap: json['iboolMap'] == null
          ? const IMapConst({})
          : IMap<bool, String>.fromJson(
              json['iboolMap'] as Map<String, dynamic>,
              (value) => value as bool,
              (value) => value as String),
      iIntMap: json['iIntMap'] == null
          ? const IMapConst({})
          : IMap<int, String>.fromJson(json['iIntMap'] as Map<String, dynamic>,
              (value) => value as int, (value) => value as String),
      iDurationMap: json['iDurationMap'] == null
          ? const IMapConst({})
          : IMap<Duration, String>.fromJson(
              json['iDurationMap'] as Map<String, dynamic>,
              (value) => Duration(microseconds: value as int),
              (value) => value as String),
      iDoubleMap: json['iDoubleMap'] == null
          ? const IMapConst({})
          : IMap<double, String>.fromJson(
              json['iDoubleMap'] as Map<String, dynamic>,
              (value) => (value as num).toDouble(),
              (value) => value as String),
      iObjectMap: json['iObjectMap'] == null
          ? const IMapConst({})
          : IMap<Object, String>.fromJson(
              json['iObjectMap'] as Map<String, dynamic>,
              (value) => value as Object,
              (value) => value as String),
      iUriMap: json['iUriMap'] == null
          ? const IMapConst({})
          : IMap<Uri, String>.fromJson(
              json['iUriMap'] as Map<String, dynamic>,
              (value) => Uri.parse(value as String),
              (value) => value as String),
      intMap: (json['intMap'] as Map<String, dynamic>?)?.map(
            (k, e) => MapEntry(int.parse(k), e as String),
          ) ??
          const {},
    );

Map<String, dynamic> _$SerializableExampleToJson(
        SerializableExample instance) =>
    <String, dynamic>{
      'iMap': instance.iMap.toJson(
        (value) => value.toIso8601String(),
        (value) => value,
      ),
      'iEnumMap': instance.iEnumMap.toJson(
        (value) => _$TestEnumEnumMap[value]!,
        (value) => value,
      ),
      'iStringMap': instance.iStringMap.toJson(
        (value) => value,
        (value) => value,
      ),
      'iBigIntMap': instance.iBigIntMap.toJson(
        (value) => value.toString(),
        (value) => value,
      ),
      'iboolMap': instance.iboolMap.toJson(
        (value) => value,
        (value) => value,
      ),
      'iIntMap': instance.iIntMap.toJson(
        (value) => value,
        (value) => value,
      ),
      'iDurationMap': instance.iDurationMap.toJson(
        (value) => value.inMicroseconds,
        (value) => value,
      ),
      'iDoubleMap': instance.iDoubleMap.toJson(
        (value) => value,
        (value) => value,
      ),
      'iObjectMap': instance.iObjectMap.toJson(
        (value) => value,
        (value) => value,
      ),
      'iUriMap': instance.iUriMap.toJson(
        (value) => value.toString(),
        (value) => value,
      ),
      'intMap': instance.intMap.map((k, e) => MapEntry(k.toString(), e)),
    };

const _$TestEnumEnumMap = {
  TestEnum.testValue: 'testValue',
};

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions