0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

freezed の jsonSerializable で Build configuration を指定したら TypeError: null: type 'Null' is not a subtype of type 'String'

Last updated at Posted at 2024-11-25

JSON のキー名に一部、 camelCase のものが残っていた。のであった・・・

Build configuration で field_rename を指定して snake_case → camelCase に変換する場合、 JSON のキー名に snake_case が残っているとその部分が読み込まれないので注意が必要。

背景

freezed

freezed を使用するとクラス定義を簡便に行える( Java での Lombok に相当)。そのなかには fromJson も定義できる。これが素晴らしい。


final List<Map<String, dynamic>> dummyJson = [
  {
    'key_a': 'aaa',
    'key_b': 'bbb',
  },
  {
    'key_a': 'AAA',
    'key_b': 'BBB',
  },
];

final List<MyEntity> entity = dummyJson.map((json) => MyEntity.fromJson(json)).toList();

このようなことができる。

Build configuration

標準だと fromJson メソッドはメンバ変数名と JSON のキー名を突合する。上のような JSON をパースする場合、クラス定義側は下のようになるだろうか。


import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:flutter/foundation.dart';

part 'data.freezed.dart';
part 'data.g.dart';

@freezed
class MyEntity with _$MyEntity {
  factory MyEntity.fromJson(Map<String, dynamic> json) => _$MyEntityFromJson(json);
  const factory AnkiCard({
    required String key_a,
    required String key_b,
  }) = _MyEntity;
}

これではメンバ変数定義が snake_case になってしまい、いかにもよろしくない。jsonSerializable の 🔗Build configuration を指定する ことで JSON の snake_case を camelCase に変換して対応づけられる。 build.yaml を作成した。

build.yaml
targets:
  $default:
    builders:
      json_serializable:
        options:
          any_map: false
          checked: false
          constructor: ""
          create_factory: true
          create_field_map: false
          create_to_json: true
          disallow_unrecognized_keys: false
          explicit_to_json: false
          field_rename: snake # これ
          generic_argument_factories: false
          ignore_unannotated: false
          include_if_null: true

field_rename🔗値 を指定した。これでクラス定義側は camelCase でメンバ変数を定義できる。よかったよかった。

エラー発生。

残念ながら万事解決とはならず、 MyEntity クラスの利用時にぬるぽが発生した。

error: TypeError: null: type 'Null' is not a subtype of type 'String'

昨日までロードできていたのに。

g.dart

ひと通り検索して分からないことを確かめてから、ひとまず生成された freezed のファイルを読むことにした。

xxx.g.dart
_$MyEntityImpl _$$MyEntityImplFromJson(Map<String, dynamic> json) =>
    _$MyEntityImpl(
      keyA: json['key_a'] as String,
      keyB: json['key_b'] as String,
    );

ここを読んで唐突に気付いた。 JSON データの中に一部 camelCase が残っていた、と・・・。

おわり

話が分かりやすいように単純化して書いているので「そんなミスあるかいな」と思われるかもしれない。しかしいくつかのことを並行していたり、ほかに怪しい部分を疑ってしまい、このようなことになった。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?