mirrors in dart not working for all elements

Issue

I am using reflection (aka dart:mirrors) in dart. First: All the code seen here works perfectly in dartium (with dart native) but only partially when compiled with dart2js and run in chrome.

I have a class called BinaryReader than reads a class from a bytestream. Here is the code (stripped the repetitive part) that does so:

  void readObject(dynamic obj) {
    var inst = reflect(obj);
    inst.type.declarations.forEach((Symbol name, DeclarationMirror decl) {
      if(decl is VariableMirror) {
        var variable = decl;
        if(variable.metadata.length == 0) {
          return;
        }

        InstanceMirror attrib = variable.metadata.first;
        if(attrib.hasReflectee == false) {
          return;
        }

        if(attrib.reflectee is Field) {
          var field = attrib.reflectee as Field;
          var value;
          switch(field.type) {
            case I8: 
              value = getInt8();
              break;

            // ...

            case V3:
              value = new Vector3(getFloat(), getFloat(), getFloat());
              break;

            default:
              value = null;
              break;
          }

          if(value == null) {
            return;
          }

          inst.setField(name, value);
        }
      }
    });
  }

Importing mirrors is done the following way:

import 'model/M4SubMesh.dart';
import 'model/M4Model.dart';
import 'package:vector_math/vector_math.dart';
@MirrorsUsed(targets: const["M4SubMesh", "M4Model", "vector_math"], override: '*')
import 'dart:mirrors';

M4SubMesh and M4Model are the library names of the respective dart files. vector_math the one of vector_math.dart

At first i read an instance of M4Header which is part of M4Model library from the stream. All the values are correct, here what it looks like:

class M4Header
{
  @Field(UI32)
  int Signature;
  @Field(UI32)
  int Version;
  @Field(UI32)
  int numSubMeshes;
  @Field(UI32)
  int ofsSubMeshes;  
}

Then later i try to read a M4SubMeshHeader which looks like this:

class M4SubMeshHeader
{
  @Field(UI32)
  int gridX, gridY, gridZ;
  @Field(F32)
  num blockSize;
  @Field(V3)
  Vector3 bboxMin, bboxMax;
}

After reading, blockSize has a random value. bboxMin and bboxMax are null. What is going wrong here?

Greetings
Cromon

Solution

Found the solution! The annotation only applies to the first element in a declaration list. So the above example actually expanded to:

class M4SubMeshHeader
{
  @Field(UI32)
  int gridX;
  int gridY;
  int gridZ;
  @Field(F32)
  num blockSize;
  @Field(V3)
  Vector3 bboxMin;
  Vector3 bboxMax;
}

In my opinion this can be considered an error, ill have a look at the documentation and if its not mentioned there report it. So in the end blockSize became the value that should have been assigned gridY which made it look like random. But – to be honest – i also have to take some blame. ‘bboxMin and bboxMax are null’, this is wrong, bboxMin wasnt null, but had invalid values but as i left a line in the code where i used bboxMax before print-ing it i thought it allready broke at bboxMin.

Greetings
Cromon

Answered By – Cromon

Answer Checked By – David Goodson (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published.