Flutter JSON Serialization - Not generating *.g.dart files

后端 未结 4 555
南笙
南笙 2021-01-12 23:18

I am new to flutter and the objective is to serialise complex JSON objects which contain other smaller objects.

Using the json_serializable: ^2.0.0 and

相关标签:
4条回答
  • 2021-01-12 23:41

    Checklist

    • your class files are underneath /lib or /bin
      • can be subdirectories under those
      • json_serializable won't search every directory for files to generate.
    • added import for json_annotation:
      • import 'package:json_annotation/json_annotation.dart';
    • you've added a part directive after import statements
      • your part file is named after your class filename (not the Class name itself), with a g added
      • e.g. for CacheItem class with ...
      • cache-item.dart class filename ...
      • part 'cache-item.g.dart'; gets corresponding part directive.
      • the part directive is not named after your actual Class, but the class file name.
    • you've added @JsonSerializable() above the class name
    • you've created a default constructor for your class.
      • It can be empty, have optional named parameters, or positional parameters.
      • As long as your class fields are accessible (either through constructor or public setters & getters), json_serializable can handle it. (i.e. don't have only _private properties and an empty constructor)
    • you've written the stub methods:
      • factory <Class>.fromJson(json) => _$ClassFromJson(json);
      • toJson() => _$ClassToJson(this)
      • stub methods are private (start with _ underscore)
      • $tub methods have the $
      • stub methods have proper CaSe (i.e. Pascal Case)
      • stub factory supplies (Map<String,dynamic> json) as argument
      • stub toJson() returns Map<String,dynamic>

    When all that is complete, try running the generator from the project root directory...

    In Flutter:

    flutter pub run build_runner build

    In pure Dart:

    pub run build_runner build

    Common Errors

    Bad state: Unexpected diagnostics:

    Seeing this output when running the build_runner is likely a problem with flutter and json_annotation depending on an incompatible version of analyzer. This happens with json_serializable versions prior to 3.5 requiring a dependency_override of analyzer to 0.39.14 or 0.39.17.

    Your first move should be to try the latest version of json_serilizable from pub.dev which apparently doesn't have this dependency problem.

    If you can't upgrade json_serializable you can try placing the override lines underneath dev_dependences:

    dev_dependencies:
      build_runner: ^1.9.0
      flutter_test:
        sdk: flutter
      json_serializable: 3.3.0
      test: ^1.14.3
    
    dependency_overrides:
      analyzer: '0.39.14'
    

    Notes

    Subclass / Parent Class

    If your class is a child of a parent class and you want to Serialize fields/properties of child only, you can annotate only the subclass. The parent class fields will automatically be found and included in the generated class files for the subclass.

    If you want to be able to serialize/deserialize both parent and child separately, go ahead and annotate the base / parent classes with @JsonSerializable as well.

    e.g. filename account.dart

    import 'package:json_annotation/json_annotation.dart';
    
    part 'account.g.dart';
    
    class AccountBase {
      int created;
      String username;
      String password;
    }
    
    @JsonSerializable()
    class Account extends AccountBase {
      int id;
    
      Account();
    
      factory Account.fromJson(Map<String,dynamic> json) => _$AccountFromJson(json);
      Map<String,dynamic> toJson() => _$AccountToJson(this);
    }
    

    Produces:

    // GENERATED CODE - DO NOT MODIFY BY HAND
    
    part of 'account.dart';
    
    // **************************************************************************
    // JsonSerializableGenerator
    // **************************************************************************
    
    Account _$AccountFromJson(Map<String, dynamic> json) {
      return Account()
        ..created = json['created'] as int
        ..username = json['username'] as String
        ..password = json['password'] as String
        ..id = json['id'] as int;
    }
    
    Map<String, dynamic> _$AccountToJson(Account instance) => <String, dynamic>{
          'created': instance.created,
          'username': instance.username,
          'password': instance.password,
          'id': instance.id,
        };
    

    Reference & Docs

    • Example project on github, relevant files under /bin/ and packages in pubspec.yaml
    • Flutter & Json
    • Json_Serializable package
    • Example from the package authors

    Example

    import 'package:json_annotation/json_annotation.dart';
    
    part 'cache-item.g.dart';
    
    @JsonSerializable()
    class CacheItem {
      int created;
      String keywords;
      String response;
    
      CacheItem(this.created, this.keywords, this.response);
    
      factory CacheItem.fromJson(Map<String,dynamic> json) => _$CacheItemFromJson(json);
      Map<String,dynamic> toJson() => _$CacheItemToJson(this);
    }
    

    Output

    // GENERATED CODE - DO NOT MODIFY BY HAND
    
    part of 'cache-item.dart';
    
    // **************************************************************************
    // JsonSerializableGenerator
    // **************************************************************************
    
    CacheItem _$CacheItemFromJson(Map<String, dynamic> json) {
      return CacheItem(
        json['created'] as int,
        json['keywords'] as String,
        json['response'] as String,
      );
    }
    
    Map<String, dynamic> _$CacheItemToJson(CacheItem instance) => <String, dynamic>{
          'created': instance.created,
          'keywords': instance.keywords,
          'response': instance.response,
        };
    
    

    Example Constructor Variant

    This example is the same as above except the constructor is missing some fields and has response as optional.

    It's fine.

    The generator will just use the public (implicit) setters after instantiating the object to assign the values.

    import 'package:json_annotation/json_annotation.dart';
    
    part 'cache-item.g.dart';
    
    @JsonSerializable()
    class CacheItem {
      int created;
      String keywords;
      String response;
    
      CacheItem({this.response});
    
      factory CacheItem.fromJson(Map<String,dynamic> json) => _$CacheItemFromJson(json);
      Map<String,dynamic> toJson() => _$CacheItemToJson(this);
    }
    

    Output

    // GENERATED CODE - DO NOT MODIFY BY HAND
    
    part of 'cache-item.dart';
    
    // **************************************************************************
    // JsonSerializableGenerator
    // **************************************************************************
    
    CacheItem _$CacheItemFromJson(Map<String, dynamic> json) {
      return CacheItem(
        response: json['response'] as String,
      )
        ..created = json['created'] as int
        ..keywords = json['keywords'] as String;
    }
    
    Map<String, dynamic> _$CacheItemToJson(CacheItem instance) => <String, dynamic>{
          'created': instance.created,
          'keywords': instance.keywords,
          'response': instance.response,
        };
    
    
    0 讨论(0)
  • 2021-01-12 23:52

    The constructor's argument shouldn't be optional

    User({this.firstName, this.lastName, this.dateOfBirth});
    

    They should be obligatory:

    User(this.firstName, this.lastName, this.dateOfBirth);
    

    And the part

    'user.g.dart';
    

    should be matching the Uppercase User class:

    part 'User.g.dart';
    
    0 讨论(0)
  • 2021-01-12 23:55

    The file name, class, and part 'Book.g.dart'; should all match.

    0 讨论(0)
  • 2021-01-13 00:02

    I had this following error

    error

    [WARNING] json_serializable:json_serializable on lib/day10/models/sentence.dart:
    Missing "part 'sentence.g.dart';".
    

    I noticed that I had to change on the model file this part 'Sentence.g.dart'; to this part 'sentence.g.dart'; in other words, I had to lowercase it.

    0 讨论(0)
提交回复
热议问题