evermos-tech
Published in

evermos-tech

Accessing Dart Class Information Using Mirror

Are you familiar with Mirror? Mirror is a package embedded in a dart code, mirror will enable the developer to write code sharing low-level code across the classes. Such as metadata, annotation, variables, methods, and many more. Annotation provides information related to specific codes, enabling developers to access metadata, variables, and methods from specific codes. For example, get children's class variables (data type, values) from the abstract / parent class. And that gives the parent class more control over the children, it will be useful for operations such as ORM, model parser, etc.

How does the parent class have access to children's variables & methods

Not only does it have access to a specific child, the mirror is also smart enough to find active children in case there is a parent class with multiple implementers.

Multiple implementer class

Not only that we can also add an annotation if we need to, and the parent will also find it with the mirror. here are the sample codes

Child class, using annotation

User class as a Model extending BaseModel, also this use Annotation for the overriding table name

Ordinary class for Metadata

This class will hold the tableName, enabling the parent class to know if there is any override intention on the child class.

ModelMirror class

ModelMirror class is used to get child class information from the parent class, as we can see there is some getter to retrieve information such as:

  1. InstanceMirror, to get the active child instance information we need to use reflect(instance), it will return an InstanceMirror. This is the lowest reflection we can get from a child class
  2. ClassMirror, class mirror is the upper reflection. The class mirror can be used to retrieve the List of VariableMirror and List of MethodMirror through declarations, and also retrieve the class metadata.
  3. List<VariableMirror> is a variables reflection, that we can retrieve from the ClassMirror
  4. List<MethodMirror> is a variables method, that we can retrieve from the ClassMirror
  5. Metadata, ordinary custom class to annotated at User model, and also saving the tableName in a variable to be retrieved latter
  6. Tablename, in this case, tableName is used for overriding table name in ORM

Notice this class is created as abstract in order to be reused/mixed with other classes

BaseModel class mix with ModelMirror for accessing child class variables from BaseModel

BaseModel is an abstract class to be extended from the child, this class contains a database operation code. This class also mixed with ModelMirror in order to access the Mirror from the parents. As we can see on this createPayload, it constructs a map<String, dynamic> from List<VariableMirror>.

createPayload using List<VariableMirror> variables

If the class is initialized with payload :

The result will be :

The reason the key case is changing from camelCase to snake_case because after getting the variable key, I had transformed it to snake case with this

TextUtil.snakeCase(
MirrorSystem.getName(variable.simpleName);
);

At this point, you can ignore this chunk of code and let focus more on retrieving the variable names & values. Take a look at recapped code

final payload = {};
for(var variable in variables){
/// MirrorSystem.getName will retrieve variable name straight from variable
/// using Symbol from variable.simpleName
var variableName = MirrorSystem.getName(variable.simpleName);
/// Meanwhile we cannot use .getField on the same manner as .getName because
/// .getField isn't a static method. And also we need the lowest part such as
/// instanceMirror to execute .getField(), it's also using Symbol from variable.simpleName
var variableValue = instanceMirror.getField(variable.simpleName);
payload[variableName] = variableValue;
}

That's it! today we learn 3 things

  1. Retrieve annotation from children's class inside the parent class
  2. Retrieve variables, and methods from children's class inside the parent class
  3. In two-way code sharing using a mirror package, not only a child class can inherit the parent class methods and variables. But also parent class that has control over the children's class

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store