atreeon / morphy

Provides a clean class definition with extra functionality including; copy with, json serializable, tostring, equals that supports inheritance and polymorphism
4 stars 2 forks source link

SubclassFromJson not defined for Superclass #4

Open burhankhanzada opened 8 months ago

burhankhanzada commented 8 months ago

I haved Human as superclass and Student as subclass and defined Student as explicitSubTypes to Human morphy annotation options with generateJson to true but getting error for _$StudentFromJson

The method '_$StudentFromJson' isn't defined for the type 'Human'.
Try correcting the name to the name of an existing method, or defining a method named '_$StudentFromJson'.dart[undefined_method](https://dart.dev/diagnostics/undefined_method)

human.dart


import 'package:morphy_annotation/morphy_annotation.dart';
import 'package:morphy_test/student.dart';

part 'human.g.dart'; part 'human.morphy.dart';

@Morphy(generateJson: true, explicitSubTypes: [$Student]) abstract class $Human { String get name; int get age; }


> student.dart
```dart
import 'package:morphy_annotation/morphy_annotation.dart';
import 'package:morphy_test/human.dart';

part 'student.g.dart';
part 'student.morphy.dart';

@Morphy(generateJson: true)
abstract class $Student implements $Human {
  String get rollNo;
}

human.morphy.dart


// ignore_for_file: UNNECESSARY_CAST
// ignore_for_file: unused_element

part of 'human.dart';

// ** // Generator: MorphyGenerator // **

///

@JsonSerializable( explicitToJson: true, ) class Human extends $Human { final String name; final int age;

/// Human({ required this.name, required this.age, }); Human._({ required this.name, required this.age, }); String toString() => "(Human-name:${name.toString()}|age:${age.toString()})"; int get hashCode => hashObjects([name.hashCode, age.hashCode]); bool operator ==(Object other) => identical(this, other) || other is Human && runtimeType == other.runtimeType && name == other.name && age == other.age; Human copyWithHuman({ String Function()? name, int Function()? age, }) { return Human.( name: name == null ? this.name as String : name() as String, age: age == null ? this.age as int : age() as int, ); }

//$Student|[]|[rollNo:String:$Student, name:String:$Human, age:int:$Human]$Human|[]|[name:String:null, age:int:null] //$Student|[]|[rollNo:String:$Student, name:String:$Human, age:int:$Human] factory Human.fromJson(Map<String, dynamic> json) { if (json['className'] == "Student") { return _$StudentFromJson( json, ); } else if (json['className'] == "Human") { return _$HumanFromJson( json, ); } else { throw UnsupportedError( "The className '${json['className']}' is not supported by the Human.fromJson constructor."); } }

// ignore: unused_field Map<Type, Object? Function(Never)> _fns = {};

Map<String, dynamic> toJson_2([Map<Type, Object? Function(Never)>? fns]) { this._fns = fns ?? {}; return toJson(); }

Map<String, dynamic> toJson() { final Map<String, dynamic> data = _$HumanToJson( this, ); // Adding custom key-value pair data['className'] = 'Human';

return data;

} }

extension $Human_changeTo_E on $Human { Human changeToHuman({ String Function()? name, int Function()? age, }) { return Human.( name: name == null ? this.name as String : name() as String, age: age == null ? this.age as int : age() as int, ); }

Student changeToStudent({ required String rollNo, String Function()? name, int Function()? age, }) { return Student.( rollNo: rollNo as String, name: name == null ? this.name as String : name() as String, age: age == null ? this.age as int : age() as int, ); } }

enum Human$ { name, age }


> student.morpgy.dart
```dart
// ignore_for_file: UNNECESSARY_CAST
// ignore_for_file: unused_element

part of 'student.dart';

// **************************************************************************
// Generator: MorphyGenerator<Morphy>
// **************************************************************************

///
///implements [$Human]
///

///

@JsonSerializable(
  explicitToJson: true,
)
class Student extends $Student implements Human {
  final String name;
  final int age;
  final String rollNo;

  ///
  ///implements [$Human]
  ///

  ///
  Student({
    required this.name,
    required this.age,
    required this.rollNo,
  });
  Student._({
    required this.name,
    required this.age,
    required this.rollNo,
  });
  String toString() =>
      "(Student-name:${name.toString()}|age:${age.toString()}|rollNo:${rollNo.toString()})";
  int get hashCode =>
      hashObjects([name.hashCode, age.hashCode, rollNo.hashCode]);
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is Student &&
          runtimeType == other.runtimeType &&
          name == other.name &&
          age == other.age &&
          rollNo == other.rollNo;
  Student copyWith_Human({
    String Function()? name,
    int Function()? age,
  }) {
    return Student._(
      name: name == null ? this.name as String : name() as String,
      age: age == null ? this.age as int : age() as int,
      rollNo: (this as Student).rollNo,
    );
  }

  Student copyWith_Student({
    String Function()? name,
    int Function()? age,
    String Function()? rollNo,
  }) {
    return Student._(
      name: name == null ? this.name as String : name() as String,
      age: age == null ? this.age as int : age() as int,
      rollNo: rollNo == null ? this.rollNo as String : rollNo() as String,
    );
  }

//$Human|[]|[name:String:$Human, age:int:$Human]$Student|[]|[name:String:null, age:int:null, rollNo:String:null]
//
  factory Student.fromJson(Map<String, dynamic> json) {
    if (json['_className_'] == "Student") {
      return _$StudentFromJson(
        json,
      );
    } else {
      throw UnsupportedError(
          "The _className_ '${json['_className_']}' is not supported by the Student.fromJson constructor.");
    }
  }

  // ignore: unused_field
  Map<Type, Object? Function(Never)> _fns = {};

  Map<String, dynamic> toJson_2([Map<Type, Object? Function(Never)>? fns]) {
    this._fns = fns ?? {};
    return toJson();
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = _$StudentToJson(
      this,
    );
    // Adding custom key-value pair
    data['_className_'] = 'Student';

    return data;
  }
}

extension $Student_changeTo_E on $Student {
  Student changeTo_Student({
    String Function()? name,
    int Function()? age,
    String Function()? rollNo,
  }) {
    return Student._(
      name: name == null ? this.name as String : name() as String,
      age: age == null ? this.age as int : age() as int,
      rollNo: rollNo == null ? this.rollNo as String : rollNo() as String,
    );
  }
}

enum Student$ { name, age, rollNo }

human.g.dart


// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'human.dart';

// ** // JsonSerializableGenerator // **

Human _$HumanFromJson(Map<String, dynamic> json) => Human( name: json['name'] as String, age: json['age'] as int, );

Map<String, dynamic> _$HumanToJson(Human instance) => <String, dynamic>{ 'name': instance.name, 'age': instance.age, };


> student.g.dart
```dart
// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'student.dart';

// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************

Student _$StudentFromJson(Map<String, dynamic> json) => Student(
      name: json['name'] as String,
      age: json['age'] as int,
      rollNo: json['rollNo'] as String,
    );

Map<String, dynamic> _$StudentToJson(Student instance) => <String, dynamic>{
      'name': instance.name,
      'age': instance.age,
      'rollNo': instance.rollNo,
    };
burhankhanzada commented 8 months ago

after cloning the repo and running the 9 Change To test in example/readme_test.dart your test passes while i have done the same thing the difference is you defined both Pet = superclass, Cat = subclass in same file at readme_test.dart while i defined each class in its own file may be this causing issue and we are not importing subclass.g.dart file in our superclass.morphy.dart

atreeon commented 8 months ago

Hi @burhankhanzada thanks for trying out Morphy. Yes, if you use the explicitSubtypes, then you must create the classes in the same file. Would that fix the problem for you?

I would like to at some point look at a way of getting it to work without that. I'll update the readme, it does say same file somewhere in there but it should be more obvious.

Perhaps I should run a check and show a warning at least when we build our code.