Reputation: 7180
Is this really the only way to get the simpleName
of an annotation in Dart?
// Annotate with this class to enable reflection.
class Reflector extends Reflectable {
const Reflector()
: super(
invokingCapability,metadataCapability
);
}
const reflector = const Reflector();
// Reflector for annotation
class MetaReflector extends Reflectable {
const MetaReflector()
: super(metadataCapability);
}
const metareflector = const MetaReflector();
@metareflector
class MyAnnotation {
final String name;
const MyAnnotation(this.name);
}
@reflector // This annotation enables reflection on A.
class A {
final int a;
A(this.a);
int valueFunction() => a;
int get value => a;
@MyAnnotation("James Bond")
String nameFunction() => "Mike";
}
Last line returns the SimpleName - seems a bit complicated?
test('> Annotation', () {
final A a = new A(10);
final InstanceMirror im = reflector.reflect(a);
final ClassMirror cm = im.type;
Map<String, MethodMirror> instanceMembers = cm.instanceMembers;
expect(instanceMembers.keys.contains("valueFunction"),isTrue);
expect(instanceMembers.keys.contains("value"),isTrue);
expect(instanceMembers.keys.contains("nameFunction"),isTrue);
final MethodMirror mm = instanceMembers["nameFunction"];
expect(mm.isRegularMethod,isTrue);
expect(mm.metadata.length,1);
final x = mm.metadata.first;
expect(x,new isInstanceOf<MyAnnotation>());
expect((x as MyAnnotation).name,"James Bond");
final InstanceMirror imAnnotation = metareflector.reflect(x);
final ClassMirror cmAnnotation = imAnnotation.type;
expect(cmAnnotation.simpleName,"MyAnnotation");
}); // end of 'Annotation' test
Upvotes: 1
Views: 339
Reputation: 1054
At the point where you test expect(x,new isInstanceOf<MyAnnotation>());
you have essentially made the result of the computation trivial: It is statically known that the name of the class of an instance of MyAnnotation
is "MyAnnotation"
.
However, if your actual usage context doesn't commit to the type of annotation statically then you would need a more dynamic approach. Obtaining a class mirror of the metadata object (as you do) is a general approach that will work, and you will also need something like the metaReflector
to get support for looking up that class mirror. Btw, I don't see why you would need the metadataCapability
on metaReflector
, but I would expect it to require a typeCapability
.
Note that the most recent versions of reflectable require a declarationsCapability
in order to use instanceMembers
and staticMembers
(it was an anomaly to support them without that capability).
If you can make things a bit more static then you can choose some intermediate solutions: You could organize your metadata into a subtype hierarchy such that every instance of the kind of metadata that you will need to handle will have a nameOfClass
method, or you could create a Map<Type, String>
that would translate every type of metadata that you will handle into its name, or you could even (forgive me ;-) use toString()
which will reveal the name of any object whose class doesn't override the toString()
from Object
.
Finally, I'd suggest that you consider using the Type
value directly if you want to treat the metadata in a "somewhat dynamic" manner: You could look up x.runtimeType
and make decisions based on comparison with MyAnnotation
just as well as you could make decisions based on comparisons with the string "MyAnnotation"
, it's only if you want to do textual things like "any class whose name matches this regex will do here" that you gain anything from going via strings.
(It should be said that runtimeType
is somewhat costly because it causes extra data to be preserved at runtime, esp. with dart2js, but that data is already needed when you use reflectable).
Upvotes: 3