Skip to content

Conversation

@Sadhorsephile
Copy link
Contributor

@Sadhorsephile Sadhorsephile commented Jan 23, 2026

Why

Sometimes backend can send response that doesn't match specified schema (e.g. the expected value is 20, the actual value is "20" or 20.0) and then generator throws an exception.

Solution

json_serializable makes it possible to specify a custom parser for specific fields, but it requires indicating such fields with an annotation. However, this approach assumes manual edit and therefore not quite suitable for generated models.

Solution here is to provide opportunity to specify parser per field type in generator configuration.

swagger_parser.yaml:

  field_parsers:
    - apply_to_type: "int"
      parser_name: "CustomIntParser"
      parser_absolute_path: "package:your_package/lib/utils/parsers/custom_int_parser.dart"
    - apply_to_type: "int?"
      parser_name: "CustomNullableIntParser"
      parser_absolute_path: "package:your_package/lib/utils/parsers/custom_nullable_int_parser.dart"

package:your_package/lib/utils/parsers/custom_nullable_int_parser.dart:

class CustomIntParser extends JsonConverter<int, Object?> {
  const CustomIntParser();
  @override
  int fromJson(Object? json) {
    if (json is int) return json;
    if (json is String) return int.parse(json);
    if (json is double) return json.toInt();

    throw FormatException("can't parse $json to int");
  }

  @override
  Object? toJson(int object) {
    return object.toString();
  }
}

class CustomNullableIntParser extends JsonConverter<int?, Object?> {
  const CustomNullableIntParser();
  @override
  int? fromJson(Object? json) {
    if (json == null) return null;
    return CustomIntParser().fromJson(json);
  }

  @override
  Object? toJson(int? object) {
    return object?.toString();
  }
}

Result after codegeneration:

some_model.dart:

import 'package:json_annotation/json_annotation.dart';
import 'package:your_package/lib/utils/parsers/custom_nullable_int_parser.dart';

part 'some_model.g.dart';

@JsonSerializable()
class SomeModel {
  const SomeModel({
    required this.id,
    required this.amount,
  });

  factory SomeModel.fromJson(Map<String, Object?> json) => _$SomeModel(json);

  @CustomIntParser()
  final int id;

  @CustomNullableIntParser()
  final int? amount;

  Map<String, Object?> toJson() => _$SomeModelToJson(this);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant