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

How would I do the Dart equivalent of this Java code?
Class<?> c = Class.forName("mypackage.MyClass");
Constructor<?> cons = c.getConstructor(String.class);
Object object = cons.newInstance("MyAttributeValue");
(From Jeff Gardner)

The Dart code:
ClassMirror c = reflectClass(MyClass);
InstanceMirror im = c.newInstance(const Symbol(''), ['MyAttributeValue']);
var o = im.reflectee;
Learn more from this doc: http://www.dartlang.org/articles/reflection-with-mirrors/
(From Gilad Bracha)

Using built_mirrors you can do it next way:
library my_lib;
import 'package:built_mirrors/built_mirrors.dart';
part 'my_lib.g.dart';
#reflectable
class MyClass {
String myAttribute;
MyClass(this.myAttribute);
}
main() {
_initMirrors();
ClassMirror cm = reflectType(MyClass);
var o = cm.constructors[''](['MyAttributeValue']);
print("o.myAttribute: ${o.myattribute}");
}

This was an issue that has plagued me until I figured that I could implement a crude from method to handle the conversion of encoded Json Objects/strings or Dart Maps to the desired class.
Below is a simple example that also handles nulls and accepts JSON (as the string parameter)
import 'dart:convert';
class PaymentDetail
{
String AccountNumber;
double Amount;
int ChargeTypeID;
String CustomerNames;
PaymentDetail({
this.AccountNumber,
this.Amount,
this.ChargeTypeID,
this.CustomerNames
});
PaymentDetail from ({ string : String, object : Map }) {
var map = (object==null) ? (string==null) ? Map() : json.decode(string) : (object==null) ? Map() : object;
return new PaymentDetail(
AccountNumber : map["AccountNumber"] as String,
Amount : map["Amount"] as double,
ChargeTypeID : map["ChargeTypeID"] as int,
CustomerNames : map["CustomerNames"] as String
);
}
}
Below is it's implementation
PaymentDetail payDetail = new PaymentDetail().from(object: new Map());
PaymentDetail otherPayDetail = new PaymentDetail().from(object: {"AccountNumber": "1234", "Amount": 567.2980908});
Once again, this is simplistic and tedious to clone throughout the project but it works for simple cases.

Related

Can I use generics in Dart like this?

I want to parse http response to Dart object,so I defined a abstract class
BaseBean:
abstract class BaseBean{
BaseBean.fromJson(Map<String, dynamic> json);
Map<String, dynamic> toJson();
}
And I used it in a function:
Future<ResultData<T>> netFetch<T extends BaseBean>(){
......
return new ResultData(T.fromJson(), result, code);
}
but T.fromJson() has an error:
The method 'fromJson' isn't defined for the class 'Type'
So,can I use generics in Dart like this?Is there a better way to solve this problem?
Yes, of course, it is possible, but only with a workaround:
T unmarshal<T>(Map map, {Type type}) {
if (type == null) {
type = T;
}
switch (type) {
case Order:
return Order.fromJson(map) as T;
case OrderItem:
return OrderItem.fromJson(map) as T;
case Product:
return Product.fromJson(map) as T;
default:
throw StateError('Unable to unmarshal value of type \'$type\'');
}
}
var order = unmarshal<Order>(data);
//
var product = unmarshal(data, type: Product) as Product;
//
var type = <String, Type>{};
types['OrderItem'] = OrderItem;
// ...
var type = types['OrderItem'];
var orderItem = unmarshal(data, type: type);
I used the same approach and I came to this solution.
I created a Map<Type, BaseBean Function(dynamic)> decoders.
It looks like
final decoders = {
MyClass: (data) => MyClass.fromJson(data),
};
and I get the function in this way
final MyClass myData = decoders[T]!(data);
You can also create a typedef for the BaseBean Function(dynamic) like this
typedef Decoder = BaseBean Function(dynamic);
So the Map<Type, BaseBean Function(dynamic)> will became Map<Type, Decoder>.

is there any way to spread a array in dart like we do in javaScript?

i have array that holds arguments which i want to pass to a constructor of a class
void main() {
var arr = ["abc", "bca"];
A(...arr); //something like that
}
class A {
String a;
String b;
A(this.a,this.b);
}
is there any way to do so. Please help me if you have any solution.
No, Dart doesn't support such a feature for now (Dart-2.1).
To avoid destructuring array at every call sites with A(arr[0], arr[1]) you can add an other constructor.
void main() {
var arr = ["abc", "bca"];
A.spread(arr);
}
class A {
String a;
String b;
A(this.a,this.b);
A.spread(List arr) : this(arr[0], arr[1]);
}
As there is no destructing in Dart, I simply do this:
var yourList: List<String> = ["first", "second", "third", etc];
var first = yourList.first;
var others = yourList.sublist(1);

Converting TypeScript to Dart

I am trying to understand some typescript but mostly works with Dart.
I see the following example code relevant to what I am doing
import {Component} from 'angular2/core';
import {Validators, MaxLengthValidator, Control, ControlGroup} from 'angular2/common';
import {isPresent} from 'angular2/src/facade/lang';
import {bootstrap} from 'angular2/platform/browser';
export class CustomValidators {
static minLengthWithDescription(minLength: number, desc: string): Function {
return (control: modelModule.Control): {[key: string]: any} => {
if (isPresent(Validators.required(control))) return null;
var v: string = control.value;
return v.length < minLength ?
{"minlength": {"requiredLength": minLength, "actualLength": v.length, "desc": desc}} :
null;
};
}
}
I can follow most of the code but what is the following really doing
return (control: modelModule.Control): {[key: string]: any} =>
Could someone who understands both language convert this small class to Dart?
Thanks
It's mostly about moving types from right to left.
I guess the confusing part is {[key: string]: any} which I think is also just the return type of the returned function. I guess it translates to Map<String,dynamic> but there is currently no way to add a return type annotation for a closure in Dart anyway. A workaround would be to create a typedef
typedef Map<String,dynamic> SomeFunc(modelModule.Control control);
class CustomValidators {
static SomeFunc minLengthWithDescription(int minLength, String desc) {
return (modelModule.Control control) {
if (isPresent(Validators.required(control))) return null;
String v = control.value;
return v.length < minLength ?
{"minlength": {"requiredLength": minLength, "actualLength": v.length, "desc": desc}} :
null;
};
}
}
I can't derive what modelModule. is from the code you provided, but I guess it is some namespace or nested scope to refer to the class Control.

Convert JS object into Dart classes

What is the best pattern to use to convert objects from Javascript to their Dart class counter parts?
// car.dart
import 'part.dart';
class Car {
String paintColor;
List<Part> parts;
}
// part.dart
class Part {
String name;
String SKU;
}
// main.dart
import 'dart:html';
import 'dart:js';
import 'car.dart';
void main() {
var body = document.querySelector('body');
body.addEventListener('carSelect', loadCarHandler, false);
}
void loadCarHandler(event) {
// this is the contents of a CustomEvent from outside dart
// goal is to convert it into Car and Parts
LinkedHashMap obj = event.detail;
/*
this is what the `obj` looks like inside the debugger
obj = _LinkedHashMap
:paintColor = 'Red'
:parts = List[2]
0 = _LinkedHashMap
:name = 'Wheel'
:SKU = 'Z123
1 = _LinkedHashMap
:name = 'Tire'
:SKU = 'Z456'
*/
}
Should I do a conversion in the handler?
Allow the constructor to take a LinkedHashMap and convert it there?
Create a factory?
Is there something built into Dart I'm not aware of that would handle this?
What is the preferred dart way of handling this?
There are several libraries that allow to create Dart object from JSON datas. See morph, dartson or serialization.
You can also avoid mirrors by adding a constructor like this :
class Car {
String paintColor;
List<Part> parts;
Car();
Car.fromJson(json)
: paintColor = json['paintColor'],
parts = json['parts'].map((e) => new Part.fromJson(e)).toList();
}
class Part {
String name;
String SKU;
Part();
Part.fromJson(json)
: name = json['name'],
SKU = json['SKU'];
}

Dynamic class method invocation in Dart

Like the question at Dynamic class method invocation in PHP I want to do this in Dart.
var = "name";
page.${var} = value;
page.save();
Is that possible?
There are several things you can achieve with Mirrors.
Here's an example how to set values of classes and how to call methods dynamically:
import 'dart:mirrors';
class Page {
var name;
method() {
print('called!');
}
}
void main() {
var page = new Page();
var im = reflect(page);
// Set values.
im.setField("name", "some value").then((temp) => print(page.name));
// Call methods.
im.invoke("method", []);
}
In case you wonder, im is an InstanceMirror, which basically reflects the page instance.
There is also another question: Is there a way to dynamically call a method or set an instance variable in a class in Dart?
You can use Dart Mirror API to do such thing. Mirror API is not fully implemented now but here's how it could work :
import 'dart:mirrors';
class Page {
String name;
}
main() {
final page = new Page();
var value = "value";
InstanceMirror im = reflect(page);
im.setField("name", value).then((_){
print(page.name); // display "value"
});
}
You can use Serializable
For example:
import 'package:serializable/serializable.dart';
#serializable
class Page extends _$PageSerializable {
String name;
}
main() {
final page = new Page();
var attribute = "name";
var value = "value";
page["name"] = value;
page[attribute] = value;
print("page.name: ${page['name']}");
}

Resources