Json_serializable.dart: Serialization fails: type 'String' is not a subtype of type 'int' in type cast

Created on 25 Jun 2019  路  6Comments  路  Source: google/json_serializable.dart

It seems that the fromJson needs to parse an int instead of casting the String to an int.

Dart Version:

Dart VM version: 2.3.0-dev.0.1.flutter-1f1592edce (Tue Apr 23 00:32:54 2019 +0000) on "linux_x64"

pubspec.yaml :

```dart
environment:
sdk: '>=2.2.0 <3.0.0'

dependencies:
json_annotation: ^2.4.0

dev_dependencies:
pedantic: ^1.0.0
test: ^1.0.0
build_runner: ^1.6.0
json_serializable: ^3.0.0
```

Annotated class:

```dart
import 'package:json_annotation/json_annotation.dart';

part 'json.g.dart';

@JsonSerializable()
class JsonObject extends Object {
final int number;

JsonObject(this.number);

factory JsonObject.fromJson(Map json) => _$JsonObjectFromJson(json);
}
```

Generated class:

```dart
part of 'json.dart';

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

JsonObject _$JsonObjectFromJson(Map json) {
return JsonObject(json['number'] as int);
}

Map _$JsonObjectToJson(JsonObject instance) =>
{'number': instance.number};
```

Function using class:

```dart
import 'dart:convert';
import 'json.dart';

int calculate() {
final String jsonString = '{"number": "5"}';
final Map jsonMap = jsonDecode(jsonString);
JsonObject jsonObject = JsonObject.fromJson(jsonMap);
int number = jsonObject.number;

return number * 6;
}
```

Error message:

Unhandled exception:
type 'String' is not a subtype of type 'int' in type cast

0 _$JsonObjectFromJson

package:serializer_fail/json.g.dart:10

1 new JsonObject.fromJson

package:serializer_fail/json.dart:11

2 calculate

package:serializer_fail/serializer_fail.dart:7

3 main

../bin/main.dart:4

4 _startIsolate. (dart:isolate-patch/isolate_patch.dart:298:32)

5 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:171:12)

If I hand edit the generated class to change it from a cast to parsing an int the program works.

Edited generated class:

dart - return JsonObject(json['number'] as int); + return JsonObject(int.parse(json['number']));

Exception is now gone:

Hello world: 30!
Exited

Thanks.

Most helpful comment

Thank you for the quick response. Sorry about that. You are correct.

Just for reference to anyone may happen upon this. Here is how I modified the annotated class to fix my issue:

import 'package:json_annotation/json_annotation.dart';

part 'json.g.dart';

@JsonSerializable()
class JsonObject extends Object {
  @JsonKey(fromJson: _stringToInt, toJson: _stringFromInt)
  final int number;

  JsonObject(this.number);

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

  static int _stringToInt(String number) => number == null ? null : int.parse(number);
  static String _stringFromInt(int number) => number?.toString();
}

Edited thanks.

All 6 comments

import 'dart:convert';
import 'json.dart';

int calculate() {
  final String jsonString = '{"number": 5}';
  final Map<String, dynamic> jsonMap = jsonDecode(jsonString);
  JsonObject jsonObject = JsonObject.fromJson(jsonMap);
  int number = jsonObject.number;

  return number * 6;
}

If you have JSON where the number is encoded as a number (not a String) everything works fine.

You'll need to use a custom converter to solve this if your input data is unchangeable.

See https://github.com/dart-lang/json_serializable/blob/master/example/lib/example.dart#L47

Thank you for the quick response. Sorry about that. You are correct.

Just for reference to anyone may happen upon this. Here is how I modified the annotated class to fix my issue:

import 'package:json_annotation/json_annotation.dart';

part 'json.g.dart';

@JsonSerializable()
class JsonObject extends Object {
  @JsonKey(fromJson: _stringToInt, toJson: _stringFromInt)
  final int number;

  JsonObject(this.number);

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

  static int _stringToInt(String number) => number == null ? null : int.parse(number);
  static String _stringFromInt(int number) => number?.toString();
}

Edited thanks.

```dart
static String _stringFromInt(int number) => number?.toString();
````

static String intSafeToString(dynamic jsonVal) {
      return jsonVal?.toString()?? "";
  }

this can handle int and string.

I used Freezed package and need generating json . But when get response from API faced error type 'String' is not a subtype of type 'int' in type cast
@broofus Already try your approach , but get this error.

Error

Launching lib\main.dart on Redmi Note 4 in debug mode...

Compiler message:
lib/src/network/models/utang/utang_model.freezed.dart:223:20: Error: Getter not found: '_stringToInt'.
@JsonKey(fromJson: _stringToInt, toJson: _stringFromInt)
                   ^^^^^^^^^^^^
lib/src/network/models/utang/utang_model.freezed.dart:223:42: Error: Getter not found: '_stringFromInt'.
@JsonKey(fromJson: _stringToInt, toJson: _stringFromInt)
                                         ^^^^^^^^^^^^^^

Compiler message:
lib/src/network/models/utang/utang_model.freezed.dart:223:20: Error: Getter not found: '_stringToInt'.
@JsonKey(fromJson: _stringToInt, toJson: _stringFromInt)
                   ^^^^^^^^^^^^
lib/src/network/models/utang/utang_model.freezed.dart:223:42: Error: Getter not found: '_stringFromInt'.
@JsonKey(fromJson: _stringToInt, toJson: _stringFromInt)
                                         ^^^^^^^^^^^^^^
Target kernel_snapshot failed: Exception: Errors during snapshot creation: null
build failed.

FAILURE: Build failed with an exception.

* Where:
Script 'C:\flutter\flutter\packages\flutter_tools\gradle\flutter.gradle' line: 882

* What went wrong:
Execution failed for task ':app:compileFlutterBuildDebug'.
> Process 'command 'C:\flutter\flutter\bin\flutter.bat'' finished with non-zero exit value 1

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 23s
Exception: Gradle task assembleDebug failed with exit code 1
Exited (sigterm)

Model

@freezed
abstract class UtangModel with _$UtangModel {
  @JsonSerializable(fieldRename: FieldRename.snake)
  @JsonKey(fromJson: _stringToInt, toJson: _stringFromInt)
  const factory UtangModel({
    String idUtang,
    UserGoogleModel pembertang,
    UserGoogleModel pengutang,
    int totalUtang,
    int sisaUtang,
    DateTime tglKembali,
    String status,
    String keterangan,
    String selfie,
    String ttd,
    DateTime createdDate,
  }) = _UtangModel;
  factory UtangModel.fromJson(Map<String, dynamic> json) => _$UtangModelFromJson(json);
  static int _stringToInt(String number) => number == null ? null : int.parse(number);
  static String _stringFromInt(int number) => number?.toString();
}
Was this page helpful?
0 / 5 - 0 ratings