Accessing library internal fields with mirror

137 views Asked by At

Trying to access a private (package internal) field got me in a strange situation. My Class "Properties" has a internal field named '_forceAccum'. Trying to get the value of it fails for me using this code:

InstanceMirror bodyMirror = reflect(props);
var value = propsMirror.getField(new Symbol('_forceAccum'));

but if I use this instead:

InstanceMirror bodyMirror = reflect(props);
var value = propsMirror.getField(new Symbol('_forceAccum@434525364'));

it works. (I got the "@..." from iterating through the symbols (.toString()) from the class mirror).

Is it supposed to work this way? Is it safe or will it change in the next version? (I'm using 1.7.2) or does it just work by pure happenstance?

2

There are 2 answers

0
lrn On BEST ANSWER

Your problem is that you have a library private name. It's name isn't just _forceAccum, it's a special symbol related to _forceAccum that is unique to the library, but different from a _forceAccum in another library.

To create the private symbol using mirrors, you must use MirrorSystem.getSymbol as: MirrorSystem.getSymbol("_forceAccum", libraryMirrorOfLibrary). This creates a library-private symbol for that particular library. You can't create a private symbol without either specifying the library that it's private to, or by being in the library (#_forceAccum will create the correct symbol for the library that it occurs in).

The other alternative, which you used, is to look through the library and find the already existing symbol there:

var forceAccumSymbol = 
    libraryMirrorOfLibrary.declarations.keys
                          .where((n) => MirrorSystem.getName(n) == "_forceAccum")
                          .first;

(if the declaration is a top-level declaration).

The _forceAccum@something name that you are seeing is the VM's way of making a name library private. It's not going to work if compiled with dart2js, and it's probably not going to have the same something on each run, so you can't can't put it into your code.

0
Florian Loitsch On

The behavior is not guaranteed.

If you were in the same library you could probably build the symbol yourself (either with #_forceAccum or with const Symbol("_forceAccum") or new Symbol("_forceAccum")).

The best way to get to the symbol from outside its library is probably to find it (testing with toString() and then cache it.