0

I have a following class:


import 'package:json_annotation/json_annotation.dart';

part 'account_filter.g.dart';

@JsonSerializable()
class AccountFilter {
  double latitude = 0;
  double longitude = 0;
  String city = "";
  String country = "";
  int minAge = 18;
  int maxAge = 99;
  int gender = 1;

  AccountFilter(
    this.latitude,
    this.longitude,
    this.city,
    this.country,
    this.minAge,
    this.maxAge,
    this.gender,
  );

  factory AccountFilter.fromJson(Map<String, dynamic> json) => _$AccountFilterFromJson(json);

  Map<String, dynamic> toJson() => _$AccountFilterToJson(this);
}

After dart run build_runner build --delete-conflicting-outputs generated file looks like this:

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'account_filter.dart';

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

AccountFilter _$AccountFilterFromJson(Map<String, dynamic> json) =>
    AccountFilter(
      (json['latitude'] as num).toDouble(), // <-- IMPORTANT!!!
      (json['longitude'] as num).toDouble(), // <-- IMPORTANT!!!
      json['city'] as String,
      json['country'] as String,
      json['minAge'] as int,
      json['maxAge'] as int,
      json['gender'] as int,
    );

Map<String, dynamic> _$AccountFilterToJson(AccountFilter instance) =>
    <String, dynamic>{
      //... some code
    };

During deserialization I receive the following error type 'String' is not a subtype of type 'num' in type cast

Of course, the problem lies in the line

json['latitude'] as num).toDouble(),

How can I solve this problem elegantly? In my original solution I set longitude and latitude to be strings, renamed them to longitudeString and latitudeString and created two getters:

  double get latitude => double.parse(latitudeString);
  double get longitude => double.parse(longitudeString);

but I am looking for more convenient solution.

Draško
  • 2,119
  • 4
  • 41
  • 73
  • No. That is the code generated by standard `json_serializable` package used for json serialization and deserialization. I know what I would do if I do it manually, but I have many models, so this package is the only reasonable solution. – Draško May 25 '23 at 17:11
  • Oh, sorry, I didn't see that. This is just my error while copy/paste my code with solution where I used Strings instead of doubles. Thanks for pointing out. I've changed it. – Draško May 25 '23 at 17:39

1 Answers1

1

This is how I solved it.

First, I defined public method:

double toDouble(String number) {
  return double.parse(number);
}

I've made the following changes to class AccountFilter:

@JsonSerializable()
class AccountFilter {
  @JsonKey(fromJson: toDouble)
  double latitude;
  @JsonKey(fromJson: toDouble)
  double longitude;
  String city = "";
  String country = "";
  int minAge = 18;
  int maxAge = 99;
  int gender = 1;

AccountFilter(
    this.latitude,
    this.longitude,
    this.city,
    this.country,
    this.minAge,
    this.maxAge,
    this.gender,
  );

  factory AccountFilter.fromJson(Map<String, dynamic> json) => _$AccountFilterFromJson(json);

  Map<String, dynamic> toJson() => _$AccountFilterToJson(this);
}

Basically, I set the method toDouble as a fromJson parameter in @JsonKey annotation used for correctly parsing the data.

Draško
  • 2,119
  • 4
  • 41
  • 73
  • 1
    Ah, if your JSON is storing floating-point numbers as strings (i.e., `latitude: "12.34"` instead of `latitude: 12.34`), then yeah, I think this is the way to go. You should be able to do `@JsonKey(fromJson: double.parse)` directly without needing to create a `toDouble` function though. – jamesdlin May 25 '23 at 18:15
  • I will try that. Sounds reasonable. Thanks! – Draško May 25 '23 at 18:16