google / reflectable.dart

Reflectable is a Dart library that allows programmers to eliminate certain usages of dynamic reflection by specialization of reflective code to an equivalent implementation using only static techniques. The use of dynamic reflection is constrained in order to ensure that the specialized code can be generated and will have a reasonable size.
https://pub.dev/packages/reflectable
BSD 3-Clause "New" or "Revised" License
381 stars 57 forks source link

Unable to gen reflectable on flutter with json_serializable #245

Closed cyberpwnn closed 3 years ago

cyberpwnn commented 3 years ago

It's pretty simple, I'm trying to have a json_serializable object that i can query field names / update field names via an Instance mirror the main reason is because I have a subclasses with jsonserializable (different types which fit in a parent json object) but ignoring all of that, I'm not sure how to setup very basic reflection.

import 'package:json_annotation/json_annotation.dart';
import 'package:myguide/arctic/builder/format/actions/action_navigate_pop.dart';
import 'package:myguide/arctic/builder/format/actions/action_navigate_push.dart';
import 'package:myguide/mycore/util/l.dart';
import 'package:myguide/reflector.dart';
import 'package:reflectable/reflectable.dart';

part 'action.g.dart'; // json_serializable generated

@Reflectable()
@JsonSerializable(explicitToJson: true, includeIfNull: false)
class GuideAction {
  // This is a field i would want to query about / update via an instance mirror
  GuideActionType type = GuideActionType.NAVIGATE_PUSH;

  // Right here i'm trying to simply get a list of fields.
  // It should return ["type"], but hopefully additional fields from subclasses
  List<String> getComponentNames() {
    List<String> v = <String>[];

    InstanceMirror mirror = Reflector.r.reflect(this);
    mirror.type.declarations.forEach((key, value) {
      v.add(value.simpleName);
    });

    return v;
  }

///////////////////////////////////////////////////////////////////////////////////////////////
  GuideAction({this.type = GuideActionType.NAVIGATE_PUSH});

  factory GuideAction.fromJson(Map<String, dynamic> json) {
    GuideAction c = _$GuideActionFromJson(json);

    switch (c.type) {
      case GuideActionType.NAVIGATE_PUSH:
        return ActionNavigatePush.fromJson(json);
      case GuideActionType.NAVIGATE_POP:
        return ActionNavigatePop.fromJson(json);
    }

    L.w("Unsupported Action Type ${c.type}");
    return c;
  }

  Map<String, dynamic> toJson() => _$GuideActionToJson(this);
}

enum GuideActionType { NAVIGATE_PUSH, NAVIGATE_POP }

I'm testing the reflection in a random flutter widget when a button is tapped

ComponentList list = ComponentList();
list.getComponentNames().forEach((element) {
  L.v("Field: $element"); // Simply logs (verbose)
});

However when running the build_runner

[INFO] Generating build script...
[INFO] Generating build script completed, took 331ms

[INFO] Initializing inputs
[INFO] Reading cached asset graph...
[INFO] Reading cached asset graph completed, took 120ms

[INFO] Checking for updates since last build...
[INFO] Checking for updates since last build completed, took 686ms

[INFO] Running build...
[INFO] 1.1s elapsed, 1/17 actions completed.
[INFO] 2.1s elapsed, 1/17 actions completed.
[INFO] 3.2s elapsed, 1/17 actions completed.
[INFO] 4.2s elapsed, 1/17 actions completed.
[INFO] 14.4s elapsed, 1/17 actions completed.
[INFO] 15.5s elapsed, 19/20 actions completed.
[SEVERE] reflectable:reflectable on lib/main.dart:
Metadata has type Reflectable, but is not an instance of a direct subclass of Reflectable
[SEVERE] reflectable:reflectable on lib/main.dart:
Metadata has type Reflectable, but is not an instance of a direct subclass of Reflectable
[SEVERE] reflectable:reflectable on lib/main.dart:
Metadata has type Reflectable, but is not an instance of a direct subclass of Reflectable
[SEVERE] reflectable:reflectable on lib/main.dart:
Metadata has type Reflectable, but is not an instance of a direct subclass of Reflectable
[SEVERE] reflectable:reflectable on lib/main.dart:
Metadata has type Reflectable, but is not an instance of a direct subclass of Reflectable
[SEVERE] reflectable:reflectable on lib/main.dart:
Metadata has type Reflectable, but is not an instance of a direct subclass of Reflectable
[SEVERE] reflectable:reflectable on lib/main.dart:
Metadata has type Reflectable, but is not an instance of a direct subclass of Reflectable
[SEVERE] reflectable:reflectable on lib/main.dart:
Metadata has type Reflectable, but is not an instance of a direct subclass of Reflectable
[SEVERE] reflectable:reflectable on lib/main.dart:
Metadata has type Reflectable, but is not an instance of a direct subclass of Reflectable
[SEVERE] reflectable:reflectable on lib/main.dart:
Metadata has type Reflectable, but is not an instance of a direct subclass of Reflectable
[SEVERE] reflectable:reflectable on lib/main.dart:
Metadata has type Reflectable, but is not an instance of a direct subclass of Reflectable
[SEVERE] reflectable:reflectable on lib/main.dart:
Metadata has type Reflectable, but is not an instance of a direct subclass of Reflectable
[SEVERE] reflectable:reflectable on lib/main.dart:
Metadata has type Reflectable, but is not an instance of a direct subclass of Reflectable
[SEVERE] reflectable:reflectable on lib/main.dart:
Metadata has type Reflectable, but is not an instance of a direct subclass of Reflectable
[SEVERE] reflectable:reflectable on lib/main.dart:
Metadata has type Reflectable, but is not an instance of a direct subclass of Reflectable
[SEVERE] reflectable:reflectable on lib/main.dart:
Metadata has type Reflectable, but is not an instance of a direct subclass of Reflectable
[SEVERE] reflectable:reflectable on lib/main.dart:
Metadata has type Reflectable, but is not an instance of a direct subclass of Reflectable
[SEVERE] reflectable:reflectable on lib/main.dart:
Metadata has type Reflectable, but is not an instance of a direct subclass of Reflectable
[SEVERE] reflectable:reflectable on lib/main.dart:
Metadata has type Reflectable, but is not an instance of a direct subclass of Reflectable
[SEVERE] reflectable:reflectable on lib/main.dart:
Metadata has type Reflectable, but is not an instance of a direct subclass of Reflectable
[SEVERE] reflectable:reflectable on lib/main.dart:
Metadata has type Reflectable, but is not an instance of a direct subclass of Reflectable
[SEVERE] reflectable:reflectable on lib/main.dart:
Metadata has type Reflectable, but is not an instance of a direct subclass of Reflectable
[SEVERE] reflectable:reflectable on lib/main.dart:
Metadata has type Reflectable, but is not an instance of a direct subclass of Reflectable
[WARNING] reflectable:reflectable on lib/main.dart:
/myguide/lib/reflector.dart:10:7: This reflector does not match anything
[INFO] 17.2s elapsed, 30/42 actions completed.
[INFO] 18.4s elapsed, 54/55 actions completed.
[INFO] Running build completed, took 18.7s

[INFO] Caching finalized dependency graph...
[INFO] Caching finalized dependency graph completed, took 81ms

[SEVERE] Failed after 18.8s
pub finished with exit code 1

Im not using any reflection in lib/main.dart nor is it reflectable. Im not sure what i'm doing wrong here.

eernstg commented 3 years ago

It is not useful to use @Reflectable() as an annotation on a class, that will just make it impossible to run the reflectable code generator.

The intended approach is that you have an immediate subclass of Reflectable which is used to declare a specific level of reflection support, e.g.,

class Reflector extends Reflectable {
  const Reflector()
      : super(instanceInvokeCapability, newInstanceCapability,
            declarationsCapability);
}

const reflector = Reflector();

and then you'd annotate the relevant classes using @reflector, e.g.,

@reflector
class GuideAction {
  ...
}

If there is no constant like reflector then you can also use @Reflector().

Said Reflector class (and accompanying reflector constant, if available) are used to specify a particular amount of reflection support. In the example above, you'll get support for invocation of instance members (because instanceInvokeCapability is included), for invocation of constructors (because of newInstanceCapability), and so on.

If the JSON package you are using is this one then I don't think there is any support for reflectable. So you'd need to write your own Reflector class.

Check out the tests in order to see a bunch of examples; searching for extends Reflectable will give you relevant hits. The test programs also show how to get access to the generated code (by having an import of a library whose name is of the form *.reflectable.dart). To get an overview of the features, take a look at 'The Design of Reflectable Capabilities'.

@cyberpwnn, I'll close this issue. Please create new ones as needed if you encounter any issues.

eernstg commented 3 years ago

@cyberpwnn, does it work now? ;-)