Create an instance of an object from a String/Symbol without the Class in Dart?

Issue

I know that it is possible to create an instance from a symbol like is shown in this link:

Create an instance of an object from a String in Dart?

But this doesn’t work for me since what I want to do is create an instance without having the class.

This problem is caused because I have One class with an internal List:

class MyNestedClass {
  String name;
}

class MyClass {
  int i, j;
  String greeting;
  List<MyNestedClass> myNestedClassList;
}

And I want to convert a map to this class:

   {
        "greeting": "hello, there",
        "i": 3,
        "j": 5,
        "myNestedClassList": [
           {
             "name": "someName1"
           },{
             "name": "someName2"
           }
        ]
    }

right now I am doing something like this:

 static void jsonToObject(String jsonString, Object object) {
    Map jsonMap = JSON.decode(jsonString); //Convert the String to a map
    mapToObject(jsonMap, object); //Convert the map to a Object
  }

  static void mapToObject(Map jsonMap, Object object) {
    InstanceMirror im = reflect(object); //get the InstanceMirror of the object
    ClassMirror cm = im.type; //get the classMirror of the object

    jsonMap.forEach((fieldNameStr, fieldValue) { // For each element in the jsonMap
      var fieldName = new Symbol(fieldNameStr); // convert the fieldName in the Map to String

      if (isPrimitive(fieldValue)) { // if fieldValue is primitive (num, string, or bool
              im.setField(fieldName, fieldValue); //set the value of the field using InstanceMirror
      } else if (fieldValue is List) { // else if the fieldValue is a list
          ClassMirror listCm = (cm.declarations[fieldName] as VariableMirror).type; //get the class mirror of the list
          var listReflectee = listCm.newInstance(const Symbol(''), []).reflectee; //create an instance of the field

          for(var element in fieldValue) { //for each element in the list
            if(!isPrimitive(element)) { // if the element in the list is a map (i.e not num, string or bool)
               var listType = listCm.typeArguments[0]; //get the TypeMirror of the list (i.e MyNestedClass from List<MyNestedClass>)

               //This is the line that doesn't work correctly
               //It should be something like:
               //
               //     ClassMirror.fromSymbol(listType.simpleName).newInstance(const Symbol(''), []);
               //
               var listObject = (listType as ClassMirror).newInstance(const Symbol(''), []); //create an instance of the specified listType

               mapToObject(element, listObject); //convert the element to Object
            }
            listReflectee.add(element); //add the element to the list
          };
      } else { //else (the field value is a map
        ClassMirror fieldCm = (cm.declarations[fieldName] as VariableMirror).type; // get the field ClassMirror from the parent declarations
        var reflectee = fieldCm.newInstance(const Symbol(''), []).reflectee; //create an instance of the field
        mapToObject(fieldValue, reflectee); // convert the fieldValue, which is a map, to an object
        im.setField(fieldName, reflectee); // set the value of the object previously converted to the corresponding field
      }
    });
  }

As you can see the lines that are not actually working are:

var listType = listCm.typeArguments[0]; //get the TypeMirror of the list (i.e MyNestedClass from List<MyNestedClass>)
var listObject = (listType as ClassMirror).newInstance(const Symbol(''), []); //create an instance of the specified listType

since they are creating an instance on localClassMirror and not on MyNestedClass. I’m looking for a method similar to:

 ClassMirror.fromSymbol(listType.simpleName).newInstance(const Symbol(''), []);

you can see the full source code in the next URL:

DSON Source Code

Solution

If you have the full qualified name of the class you should be able to find the type using libraryMirror and then it should be similar to your linked question to create an instance.
I haven’t done this myself yet and have not code at hand.

see also: how to invoke class form dart library string or file

An alternative approach would be to create a map at application initialization time where you register the supported types with their name or an id and look up the type in this map (this is like it’s done in Go)

Answered By – Günter Zöchbauer

Answer Checked By – Robin (FlutterFixes Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *