Skip to content

Conversation

@Sadhorsephile
Copy link
Contributor

Why

Sometimes backend can send response that not match specified schema (e.g. expected value is 20, actual is "20" or 20.0) and then generator will throw an exception.

Solution

json_serializable makes it possible to specify a custom parser for specific fields, but it requires to indicate such fields with an annotation. However this way supposes 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