Search code examples
flutterdartgoogle-cloud-firestorejson-serializablejson-annotation

How to generate methods in `PerFieldToJson` using `json_serializable`?


Minimum reproducible code:

// foo.dart
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:cloud_firestore_odm/cloud_firestore_odm.dart';
import 'package:json_annotation/json_annotation.dart';

part 'foo.g.dart';

@JsonSerializable(
  createFieldMap: true,
  createPerFieldToJson: true,
)
class Foo extends Bar {
  final int age;
  Foo(this.age) : super(category: 'c');
}

abstract class Bar {
  final String category;
  Bar({required this.category});
}

@Collection<Foo>('foo')
final fooRef = FooCollectionReference();

Running dart run build_runner build -d, will generate foo.g.dart with errors in the following method:

// foo.g.dart
...
@override
FooQuery whereCategory({
  Object? isEqualTo = _sentinel,
  ...
}) {
  return _$FooQuery(
    _collection,
    $referenceWithoutCursor: $referenceWithoutCursor.where(
      _$FooFieldMap['category']!,
      isEqualTo: isEqualTo != _sentinel
          ? _$FooPerFieldToJson.category(isEqualTo as String) // <-- Error
          : null,
      ...
    ),
    $queryCursor: $queryCursor,
  );
}
...

Problem:

The error occurs because the generated _$FooPerFieldToJson doesn't have the category field, it only has the age field.

// foo.g.dart
abstract class _$FooPerFieldToJson {
  // ignore: unused_element
  static Object? age(int instance) => instance;
}

How can I generate the category field?


Solution

  • enter image description here

    You can add these constructor: toJson and fromJson and i think the problem is you define the category value on your super in Foo. check my code below: i have String name on Foo constructor and pass the value to super class which is Bar

    fromJson toJson constructor are requred to generate json to class conversion

    import 'package:json_annotation/json_annotation.dart';
    
    part 'foo_bar.g.dart';
    
    @JsonSerializable()
    class Foo extends Bar {
      Foo({
        required this.age,
        required String name,
      }) : super(name);
    
      factory Foo.fromJson(Map<String, dynamic> json) => _$FooFromJson(json);
      Map<String, dynamic> toJson() => _$FooToJson(this);
    
      String? age;
    }
    
    class Bar {
      Bar(this.name);
      final String name;
    }
    

    then run generation: flutter pub run build_runner build --delete-conflicting-outputs

    drop a comment if i missed something