Json_serializable.dart: Cannot use references to abstract base classes

Created on 17 Feb 2020  Â·  6Comments  Â·  Source: google/json_serializable.dart

Attempting to use a abstract base class as a field inside another class causes a code gen error.
eg. extending the working example from an earlier bug:

import 'package:json_annotation/json_annotation.dart';

part 'temp.g.dart';

abstract class ItemCore {
  final int price;

  ItemCore(this.price);
}

@JsonSerializable()
class Item extends ItemCore {
  int count;
  int itemNumber;
  bool isRushed;

  Item(int price) : super(price);

  factory Item.fromJson(Map<String, dynamic> json) => _$ItemFromJson(json);
}

@JsonSerializable()
class ItemContainer {
  final ItemCore core;

  ItemContainer(this.core);

  factory ItemContainer.fromJson(Map<String, dynamic> json) =>
      _$ItemContainerFromJson(json);
}

causes an error of:

[INFO] Running build...
[SEVERE] json_serializable:json_serializable on lib/models/temp.dart:
Error running JsonSerializableGenerator
Could not generate `fromJson` code for `core`.
None of the provided `TypeHelper` instances support the defined type.
package:flutterette/models/temp.dart:24:18
   â•·
24 │   final ItemCore core;
   │                  ^^^^
   ╵
[INFO] Running build completed, took 862ms

Changing the field to the inheriting class works fine: final Item core;
As does making the base class not abstract but in my actual codebase I really would like it to be abstract.

Not sure if I am missing something obvious here? Googling around and searching past issues here I haven't found anything to help.

This is using:

dev_dependencies:
  flutter_test:
    sdk: flutter

  build_runner: ^1.7.4
  json_serializable: ^3.2.5

and Flutter: [✓] Flutter (Channel stable, v1.12.13+hotfix.8, on Linux

Most helpful comment

So my current workaround is to mark the abstract class as serialisable but not generate a fromJson:

@JsonSerializable(createFactory: false)
abstract class Section implements WidgetType {
...

not ideal as the analyzer complains about the unused generated toJson() but at least it means I can have my abstract baseclass and use instances of it in other model classes.
FYI I have a hand written fromJson that works well per your suggestion Kevin in 597 :

  factory Section.fromJson(Map<String, dynamic> json) {
    if (json != null && json['items'] != null) {
      return FixedSection.fromJson(json);
    } else {
      return ListSection.fromJson(json);
    }
  }

All 6 comments

So my current workaround is to mark the abstract class as serialisable but not generate a fromJson:

@JsonSerializable(createFactory: false)
abstract class Section implements WidgetType {
...

not ideal as the analyzer complains about the unused generated toJson() but at least it means I can have my abstract baseclass and use instances of it in other model classes.
FYI I have a hand written fromJson that works well per your suggestion Kevin in 597 :

  factory Section.fromJson(Map<String, dynamic> json) {
    if (json != null && json['items'] != null) {
      return FixedSection.fromJson(json);
    } else {
      return ListSection.fromJson(json);
    }
  }

i had the same problem but decided to convert abstract class into usual. For method bodies I added 'throw UnImplemneted()';

And fromJson is enhanced with switch case:

 factory NaturalResource.fromJson(Map<String, dynamic> json) {
    switch (json['type']) {
      case "FOREST":
        return Forest.fromJson(json);
      case "RIVER":
        return River.fromJson(json);
      default:
        return _$NaturalResourceFromJson(json);
    }
  }

Im having this issue but dont understand how you guys solved this one. I have some properties I in the abstract class I want included in the serialisation and deserialisation output however it seems the generated code does not take this in to account for the toJson and fromJson methods generated for the concrete classes. If I do whats @maks mentions then I dont get the serialisation/deserialisation of the abstract classes properties. Or am I missing something?

@muzzah , I converted my abstract class into normal class. Instead of implementing method bodies I just

throw Unimplemented();

To catch not extended method in the children classes.

This falls under the general issue of handling arbitrary types as field values.

To start, you'd likely need to do

@JsonSerializable()
class ItemContainer<T extends ItemCore> {
  final T core;
...

Then see https://github.com/google/json_serializable.dart/blob/master/example/lib/json_converter_example.dart#L34

Hi @kevmoo,
Bouncing back on this custom model,

  factory Section.fromJson(Map<String, dynamic> json) {
    if (json != null && json['items'] != null) {
      return FixedSection.fromJson(json);
    } else {
      return ListSection.fromJson(json);
    }
  }

I would like to implement the same with a long model,
Would you have a mainstream sample ?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

4BooM04 picture 4BooM04  Â·  3Comments

emiliodallatorre picture emiliodallatorre  Â·  3Comments

enyo picture enyo  Â·  5Comments

Nico04 picture Nico04  Â·  5Comments

ollydixon picture ollydixon  Â·  6Comments