How can I get the value of an enum from a Dart source_gen generator using ConstantReader?

74 Views Asked by At

I am using Dart source generators to build some RPC frameworks in a flutter / web view hybrid app (don't ask).

It's going very well, we have this working:

enum ServiceLifecycle {
  singleton,
  transient
}

class Service {
  final String name;
  final ServiceLifecycle lifecycle;
  const Service(this.name, [this.lifecycle = ServiceLifecycle.singleton]);
}

@Service('Greeter')
class SomeGreeterClassWithAdifferentNameThanGreeter {

  String greeting = "Hello";
  
  @ServiceMethod('ChangeGreeting')
  void changeGreeting(String greeting) {
    this.greeting = greeting;
  }

  @ServiceMethod('SayHello')
  String sayHello(String recipient) {
    return "$greeting $recipient!";
  }
}


We're auto-generating the required code for the service RPC hooks, again, going well. What's NOT going well, is this whole lifecycle enum.

Here's the generator source code;

import 'package:analyzer/dart/element/type.dart';
import 'package:source_gen/source_gen.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:build/build.dart';


class ServiceDefinitionGenerator extends GeneratorForAnnotation<Service> {
  @override
  generateForAnnotatedElement(
      Element element, ConstantReader annotation, BuildStep buildStep) {

    final registeredServiceName = annotation.read('name').stringValue;
    // registeredServiceName is the name property of the Service annotation, wonderful.



    // Where it gets lost, is here. I've tried all these different ways to get the enum value, but have no luck!
    try {
      final Object? lifecycleValue = annotation.read('lifecycle').objectValue;
      dynamic lc = lifecycleValue;
      print('read lifecycle value');
      print(lifecycleValue);
      print('lifecycleValue.toString()');
      print(lifecycleValue.toString());
      print("lc['_name'].toString()");
      print(lc['_name'].toString());
      if (lifecycleValue is String) {
        print('lifecycleValue is String');
          lifecycle = ServiceLifecycle.values.firstWhereOrNull(
            (e) => e.toString().split('.').last == lifecycleValue);
      } else if (lifecycleValue is ServiceLifecycle) {
        print('lifecycleValue is ServiceLifecycle');
        lifecycle = lifecycleValue;
      } else {
        print('lifecycleValue is not string, setting to null');
        lifecycle = null;
      }
    } catch (e) {
      print(e);
      lifecycle = null;
    }

    


    return 'The cool code';
  }

What am I doing wrong? Is there no way to get values from a ConstantReader beyond simple strings / integers? Why is the object casting failing?

I have many questions. Hopefully someone has answers.

pubspec.yaml:

name: some_package

environment:
  sdk: ^3.1.2

dependencies:
  build_runner: ^2.4.6
  json_serializable: ^6.7.1
  source_gen: ^1.4.0
  build: any
  collection: any
  analyzer: any
  change_case: ^1.1.0
  glob: ^2.0.2

dev_dependencies:
  lints: ^2.0.0
  test: ^1.21.0

0

There are 0 best solutions below