Retrieving getter values with dart:mirrors reflection - dart

I have the following code (simplified), that uses reflection to iterate a class's fields and getters and output the values. The ContainsGetter class contains a getter, and the ContainsField class contains a simple field.
Using dart:mirrors library, I can get the value of the field by using instanceMirror.getField(fieldName)), but not the getter by using instanceMirror.invoke(fieldName,[]).
The following Dart script (using the build 17463) gives the output below:
app script
import 'dart:mirrors';
class ContainsGetter { // raises an error
String get aGetter => "I am a getter";
}
class ContainsField { // works fine
String aField = "I am a field";
}
void main() {
printFieldValues(reflect(new ContainsField()));
printGetterValues(reflect(new ContainsGetter()));
}
void printFieldValues(instanceMirror) {
var classMirror = instanceMirror.type;
classMirror.variables.keys.forEach((key) {
var futureField = instanceMirror.getField(key); // <-- works ok
futureField.then((imField) => print("Field: $key=${imField.reflectee}"));
});
}
void printGetterValues(instanceMirror) {
var classMirror = instanceMirror.type;
classMirror.getters.keys.forEach((key) {
var futureValue = instanceMirror.invoke(key,[]); // <-- fails
futureValue.then((imValue) => print("Field: $key=${imValue.reflectee}"));
});
}
output
Field: aField=I am a field
Uncaught Error: Compile-time error during mirrored execution: <Dart_Invoke: did not find instance method 'ContainsGetter.aGetter'.>
Stack Trace:
#0 _LocalObjectMirrorImpl._invoke (dart:mirrors-patch:163:3)
#1 _LocalObjectMirrorImpl.invoke (dart:mirrors-patch:125:33)
(An acceptable could be that "this bit just hasn't been written yet!")

Aah, I've just worked it out. Although aGetter is like a method in its implementation, you use the getField() rather than invoke to retrieve its value.
void printGetterValues(instanceMirror) {
var classMirror = instanceMirror.type;
classMirror.getters.keys.forEach((key) {
var futureValue = instanceMirror.getField(key); // <-- now works ok
futureValue.then((imValue) => print("Field: $key=${imValue.reflectee}"));
});
}

Related

Invoke top level function with dart:mirrors

I'm struggling with how to invoke a top level function in dart. I'd like to be able to annotate a function with #Route, find all the Route annotations, then check that the annotation is on a method, and then call that method by its symbol.
What I have so far is:
class Route {
final String url;
const Route(this.url);
}
#Route('/')
void handle() {
print('Request received');
}
void main() {
var mirrorSystem = currentMirrorSystem();
var lm = mirrorSystem.isolate.rootLibrary;
for (var mirror in lm.declarations.values) {
var metadata = mirror.metadata;
for (var im in metadata) {
if (im.reflectee is Route) {
print('Route found');
// how to invoke the function handle associated with the route annotation?
}
}
}
}
From this point i'm not sure how I would then call the method. If it was a class then I could use invoke and pass in the Symbol for the method, but that doesn't work as it's not a class.
Can anyone give me some clues? Information about the mirrors library in dart is fairly sparse unfortunately.
I worked this out. For anyone who finds this, you use the LibraryMirror on rootLibrary to invoke the top level function:
void main() {
var mirrorSystem = currentMirrorSystem();
var lm = mirrorSystem.isolate.rootLibrary;
for (var mirror in lm.declarations.values) {
var metadata = mirror.metadata;
for (var im in metadata) {
if (im.reflectee is Route && mirror is MethodMirror) {
lm.invoke(mirror.simpleName, []);
// prints 'Request received'
}
}
}
}

Dart passing generic Function<T>(T t) seems to require cast, all other ways signatures don't match

With the below code as an example I can not figure out how to make the generic typed Function work with out casting as shown. Every other way I try I get some variation of
The argument type 'Null Function(Gift)' can't be assigned to the
parameter type 'dynamic Function(T)'
var present = Present<Gift>(Gift('Fancy Gift'), <T>(Gift t) {
print('${(t as Gift).name} was opened.');
});
or
The getter 'name' isn't defined for the type 'Object'
var present = Present<Gift>(Gift('Fancy Gift'), <Gift>(t) {
print('${t.name} was opened.');
});
Here is the working example with a cast.
void main() {
var present = Present<Gift>(Gift('Fancy Gift'), <T>(t) {
print('${(t as Gift).name} was opened.');
});
present.open();
}
class Present<T> {
final T _item;
final Function<T>(T t) openedCallback;
T open() {
openedCallback.call(_item);
return _item;
}
Present(this._item, this.openedCallback);
}
class Gift {
final String name;
Gift(this.name);
}
There should be a way to do this without a cast right?
Your class definition does not do what you intend:
class Present<T> {
final T _item;
final Function<T>(T t) openedCallback;
...
openedCallback is separately parameterized; its T type parameter is separate and independent from that of Present<T>. There is no need to parameterize openedCallback since you presumably want:
class Present<T> {
final T _item;
final Function(T t) openedCallback;
...
After that, you can do:
var present = Present<Gift>(Gift('Fancy Gift'), (t) {
print('${t.name} was opened.');
});
Note that doing <T>(t) { ... } or <Gift>(t) { ... } is counterproductive. That declares an anonymous function that itself is generic and is has a type parameter named T or Gift respectively.

Why does this use of callable class now work?

I am trying to get callable classes to work in dart, but I have ran into a few issues. First thing I realized is that a normal function
myFunc() {
return 'myFunc';
}
Function.apply(myFunc,null);
is not working as a callable.
Then I realized that if I do
final myFunc = () => 'myFunc';
Function.apply(myFunc,null);
this works.
So now I am trying it out with classes
class Cars {
call(Map<Symbol,dynamic> args) {
return "ride";
}
const Cars();
}
final cars = Cars();
final jobs = {cars.hashCode :cars};
void main() {
int code = cars.hashCode;
print(Function.apply(jobs[code],null));
}
but in DartPad I get the following error
Uncaught exception:
NoSuchMethodError: method not found: 'call'
Receiver: Closure 'call$1' of Instance of 'Cars'
Arguments: []
are there some restrictions on the call method? Or how it works with Function.apply() that I am not finding in the docs?
Thanks.
Your first example works fine for me, but your program needs an entry point:
myFunc() {
return 'myFunc';
}
void main() {
print(Function.apply(myFunc, null));
}
In your class example, your call method requires a Map, but you're passing null. There is no call method with zero arguments, hence the method not found: 'call' error.
One way to fix it is by adding an empty Map to the parameter list in Function.apply:
class Cars {
call(Map<Symbol,dynamic> args) {
return "ride";
}
const Cars();
}
final cars = Cars();
final jobs = {cars.hashCode :cars};
void main() {
int code = cars.hashCode;
print(Function.apply(jobs[code], [Map<Symbol,dynamic>()]));
}
It's worth noting that you can call any method on a class with any number of arguments:
class Car {
go(int speed, int wheels) {
print('$speed mph, $wheels wheels');
}
}
void main() {
var car = Car();
Function.apply(car.go, [50, 4]);
}

in Dart, given a Type name, how do you get the Type (class) itself? [duplicate]

This question already has answers here:
Create an instance of an object from a String in Dart?
(3 answers)
Closed 8 years ago.
if have a Type, using Mirrors can get the Type name. inversely, given a Type's name, how do you get the Type?
for example, from a Dart-centric version of Angular:
index.html
<form ng-controller='word?reset=true' >
...
</form>
mylib.dart
class Controller {
Controller( Brando brando, Element elem, Map args ) { ... }
}
class Word extends Controller { ... }
class LangList extends Controller { ... }
// Brando, the godfather
class Brando {
...
void compile( Element el ) {
...
// add controller
if( el.attributes.contains( 'ng-controller' ) {
var name = el.attributes.getTypeName(); <== "Word"
var args = el.attributes.getTypeArgs(); <== { 'reset': 'true' }
var type = <get type from camelized Type name> <=== how??
this.controllers.add( reflectClass(type).newInstance(
const Symbol(''), [this,el,args]).reflectee ); <=== instance from type
}
...
}
}
know how to get name of Type, how to get Type from class and Object, and know how to instantiate a Type. missing final piece - how do you derive the Type from its name?
Note: The mirror API is `unstable', so this answer may change over time.
*Note: This may (will) bloat your generated javascript see: https://api.dartlang.org/docs/channels/stable/latest/dart_mirrors/MirrorSystem.html#getSymbol*
import 'dart:mirrors';
class Bar {
}
ClassMirror findClassMirror(String name) {
for (var lib in currentMirrorSystem().libraries.values) {
var mirror = lib.declarations[MirrorSystem.getSymbol(name)];
if (mirror != null) return mirror;
}
throw new ArgumentError("Class $name does not exist");
}
void main() {
ClassMirror mirror = findClassMirror("Bar");
print("mirror: $mirror");
}
output:
mirror: ClassMirror on 'Bar'

How do I get a MethodMirror for the current function

Say I have
class RestSimulator {
#Path("/var")
void functionOne() {
final Type type = this.runtimeType;
final InstanceMirror instanceMirror = reflect(this);
final ClassMirror classMirror = instanceMirror.type;
final MethodMirror methodMirror = ?????
var metadata = methodMirror.metadata;
var path = metadata.first.reflectee;
print(path.toString()):
}
}
How can I get the MethodMirror for the calling function???
[Update]
I meant without doing something like
final MethodMirror methodMirror = functions[const Symbol('functionOne')];
So probably the main question is: How do I get the Symbol for the calling / current function?
AFAIK there's no simple way to get a reference on the current function at runtime.
I say simple because you can get the name from a StackTrace but it's really ugly and has horrible performances...
class A {
m() {
var functionName;
try {
throw '';
} catch(e, s) {
functionName = parseStackTraceToGetMethod(s.toString());
}
print(functionName); // displays A.m
}
}
parseStackTraceToGetMethod(String s) =>
s.substring(8, s.indexOf("("));
main() {
new A().m();
}

Resources