Search code examples
reflectiondartdart-mirrors

Use dart reflectable on external lib


I need to use reflectable on a third party lib but it is not working.

Consider this scenario:

Library A has the reflector declaration:

class Reflector extends Reflectable {
    const Reflector()
        : super(invokingCapability,
        typeRelationsCapability,
        metadataCapability,
        superclassQuantifyCapability,
        reflectedTypeCapability);
}

const Reflector reflector = const Reflector();

Library B has the classes that are annotated with the reflector:

import 'package:library_a/library_a.dart' show reflector;

@reflector
class whateverz {}

Now the application C needs to use reflection on whateverz class that is within library B.

My problem is that the reflectable lib can't see the whateverz class annotated. The build warns "reflector.dart: This reflector does not match anything"

And if I do "print(reflector.annotatedClasses);" it prints [] within the console.

Is this possible? To annotate the classes on a third party lib that I will end up using in an application with reflection? If yes, what am I doing wrong?


Solution

  • I suspect that the transformation isn't being performed on the correct main file.

    The transformer is capable of looking up any declaration in your program, so if there is a library in your program which is importing library B (and hence also library A) then the transformer should certainly be able to generate a mirror for class whateverz, and you should find that mirror in reflector.annotatedClasses.

    But the set of files taken into account during transformation is the transitive closure of the imports from your entry point (that is, the relevant element in the entry_points specified in your pubspec.yaml), so if you specify an entry point which is not the actual main file then the transformer may get to work with a smaller (or just different) set of libraries. For instance, if you use library A as the entry point then the transformer won't know that library B exists (assuming that library A doesn't directly or indirectly import library B), so the transformer won't discover any declarations in library B and you won't get the corresponding mirrors.

    If you are working on a library that other developers will import and use, you need to tell them to include the reflectable transformer in their pubspec.yaml and add an element to the entry_points (or check that they are using a wildcard that already matches all the desired entry points).

    You can check out three_files_test.dart to see a tiny example where a reflector in one file is used to annotate classes in different files, and you can check out meta_reflectors_test.dart to see how you can decouple reflectors, target classes, and other elements even more (e.g., by using GlobalQuantifyCapability to associate a certain reflector with a certain target class without editing the file that contains the target class).