How do I access metadata annotations from a class? - dart

I have a Dart class that is annotated with metadata:
class Awesome {
final String msg;
const Awesome(this.msg);
String toString() => msg;
}
#Awesome('it works!')
class Cool {
}
I want to see if Cool was annotated, and if so, with what. How do I do that?

Use the dart:mirrors library to access metadata annotations.
import 'dart:mirrors';
class Awesome {
final String msg;
const Awesome(this.msg);
String toString() => msg;
}
#Awesome('it works!')
class Cool {
}
void main() {
ClassMirror classMirror = reflectClass(Cool);
List<InstanceMirror> metadata = classMirror.metadata;
var obj = metadata.first.reflectee;
print(obj); // it works!
}
To learn more, read about the ClassMirror#metadata method.

Related

How to <T extend BaseClass> where BaseClass has a factory function?

Following is a simple class that provides a few helper functions for reading and writing data.
class BaseDAO<T> {
final String _modelName;
static late final StoreRef<int, Map<String, Object?>> _store;
BaseDAO(this._modelName) {
_store = intMapStoreFactory.store(_modelName);
}
Future<Database> get _db async => await AppDatabase().database;
Future<void> create(T object) async {
await _store.add(await _db, object.toJSON()); //The method 'toJSON' can't be unconditionally invoked because the receiver can be 'null'.
}
}
Now the issue with this is that the generic type T doesn't have toJSON function. I tried fixing this by writing an abstract class.
abstract class BaseModel {
Map<String, dynamic> toJSON();
factory BaseModel.fromJson(Map<String, dynamic> json);
}
and extending T with BaseModel. This presents all kinds of issues one of them being that I am unable to write an abstract class.
Any solution will be greatly appreciated.
In your case T object is empty. You need to extend it to some object which provides a method toMap().
Example:
class BaseDAO<T extends BaseModel> {
final String _modelName;
static late final StoreRef<int, Map<String, Object?>> _store;
BaseDAO(this._modelName) {
_store = intMapStoreFactory.store(_modelName);
}
Future<Database> get _db async => await AppDatabase().database;
Future<void> create(T object) async {
await _store.add(await _db, object.toMap()); // <- Dart see that this object extends to BaseModel and has a method `toMap()`,
}
}
abstract class BaseModel {
Map<String, dynamic> toMap();
}
class User extends BaseModel {
User({this.name});
final String? name;
#override
Map<String, dynamic> toMap() => {'name': name};
}
Future<void> create() async {
final user = User(name: 'Superman');
final base = BaseDAO('ModelName');
await base.create(user); // <- The user object will be added as `Map`.
}

What is an equivalent for Dart 2 to `typeof` of TypeScript?

I'm new to Dart 2. I want a class to have a property. It's a reference of other class. it's not an instance but class itself. In TypeScript, it's possible to write as below. Is there a same way in Dart 2?
class Item { }
class ItemList {
itemClass: typeof Item;
}
const itemList = new ItemList();
itemList.itemClass = Item;
UPDATED:
I added some more context. The following is minimal sample code. I want to delegate a role of instantiation to super class.
class RecordBase {
id = Math.random();
toJson() {
return { "id": this.id };
};
}
class DbBase {
recordClass: typeof RecordBase;
create() {
const record = new this.recordClass();
const json = record.toJson();
console.log(json);
}
}
class CategoryRecord extends RecordBase {
toJson() {
return { "category": "xxxx", ...super.toJson() };
};
}
class TagRecord extends RecordBase {
toJson() {
return { "tag": "yyyy", ...super.toJson() };
};
}
class CategoryDb extends DbBase {
recordClass = CategoryRecord;
}
class TagDb extends DbBase {
recordClass = TagRecord;
}
const categoryDb = new CategoryDb();
categoryDb.create();
const tagDb = new TagDb();
tagDb.create();
I have tried to make you sample code into Dart. As I told before, you cannot get a reference to a class and call the constructor on runtime based on this reference.
But you can make a reference to a method which constructs the object of you class.
import 'dart:math';
class RecordBase {
static final Random _rnd = Random();
final int id = _rnd.nextInt(100000);
Map<String, dynamic> toJson() => <String, dynamic>{'id': id};
}
abstract class DbBase {
final RecordBase Function() getRecordClass;
RecordBase record;
Map<String, dynamic> json;
DbBase(this.getRecordClass);
void create() {
record = getRecordClass();
json = record.toJson();
print(json);
}
}
class CategoryRecord extends RecordBase {
#override
Map<String, dynamic> toJson() {
return <String, dynamic>{'category': 'xxxx', ...super.toJson()};
}
}
class TagRecord extends RecordBase {
#override
Map<String, dynamic> toJson() {
return <String, dynamic>{'tag': 'yyyy', ...super.toJson()};
}
}
class CategoryDb extends DbBase {
CategoryDb() : super(() => CategoryRecord());
}
class TagDb extends DbBase {
TagDb() : super(() => TagRecord());
}
void main() {
final categoryDb = CategoryDb();
categoryDb.create(); // {category: xxxx, id: 42369}
final tagDb = TagDb();
tagDb.create(); // {tag: yyyy, id: 97809}
}
I am not really sure if the create() method should be seen as a method or a constructor. So I choose to make it a method to be closer to your code.

How to create a base factory and override it on child class in Flutter

So I have a class like Question like bellow:
#JsonSerializable()
class Question {
String id;
String content;
Question({this.id, this.content});
factory Question.fromJson(Map<String, dynamic> json) =>
_$QuestionFromJson(json);
Map<String, dynamic> toJson() => _$QuestionToJson(this);
}
Please keep in mind that those _$QuestionFromJson and _$QuestionToJson comes from this library https://pub.dev/packages/json_serializable
Say I have many class like that which have a fromJson factory and a toJson method. I want to create a base class that contains those 2 method. A base model is easy for toJson as bellow:
abstract class BaseModel {
Map<String, dynamic> toJson();
}
But what about the factory method, I have no idea how to declare them then override it simply like:
#override
factory Question.fromJson(Map<String, dynamic> json) =>
_$QuestionFromJson(json);
EDIT:
My idea of using this is because I want to create a converter utility that I only need to pass in the class of the result like Converter.listFromJson<MyClass>(jsonString). For now, the helper is:
static List<T> listFromJson<T>(jsonString, Function mappingFunction) {
return myJsonMap.map(mappingFunction).cast<T>().toList();
}
so I have to map each item by passing the map function every time I use this helper method:
Converter.listFromJson<Question>(
jsonMap, (item) => Question.fromJson(item));
There'are a few more class that needs to be convert to the list like this. I want to reuse the method without the (item) => Question.fromJson(item) method part. That's why I want to create a base class that have the factory fromJson method so that I can use it in the converter
return myJsonMap.map((item) => BaseModel.fromJson(item)).cast<T>().toList();
then I just simply call
Converter.listFromJson<Question>(jsonMap);
Thank you for your time.
i don't know if i got you correctly, that's what i understood from your question
abstract class BaseModel{
BaseModel();
BaseModel.fromJson(Map<String,dynamic> json);
}
class Question extends BaseModel{
final String id;
final String name;
Question({this.id,this.name}): super();
#override
factory Question.fromJson(Map<String, dynamic> json) {
return Question(
id: json['id'],
name: json['name']
);
}
}
void main(){
Map<String,dynamic> json = {'id': "dsajdas",'name': 'test'};
Question question = Question.fromJson(json);
print('question: ${question.id}');
}
That was my approach but you can't do such a thing. There is a workaround by declaring .fromJson(json) in a variable. Look at my sample codes, hope you can get an idea.
class Categories {
final String id;
String name;
String image;
Categories({this.id, this.name, this.image});
Categories.fromJson(dynamic json)
: id = json['id'],
name = json['name'],
image = json['image'];
}
class CategoriesModel extends AppModel<Categories> {
List<Categories> list = [];
Function fromJson = (dynamic json) => Categories.fromJson(json);
}
class AppModel<T> {
List<T> list = [];
Function fromJson;
List<T> getList() {
if (this.list.isNotEmpty) return this.list;
List<dynamic> list = GetStorage().read('tableName');
list.forEach((data) {
this.list.add(fromJson(data));
});
return this.list;
}
}

custom annotation / Metadata in dart lang

Can any one explain me the use of annotations in Dart?
In the documentations, I found this example:
library todo;
class todo {
final String who;
final String what;
const todo(this.who, this.what);
}
followed by
import 'todo.dart';
#todo('seth', 'make this do something')
void doSomething() {
print('do something');
}
so, what shall I write in the main() to get the doSomething() function executed?
thanks
Something like
import 'dart:mirrors';
import 'do_something.dart';
import 'todo.dart';
void main() {
currentMirrorSystem().libraries.forEach((uri, lib) {
//print('lib: ${uri}');
lib.declarations.forEach((s, decl) {
//print('decl: ${s}');
decl.metadata.where((m) => m.reflectee is Todo).forEach((m) {
var anno = m.reflectee as Todo;
if(decl is MethodMirror) {
print('Todo(${anno.who}, ${anno.what})');
((decl as MethodMirror).owner as LibraryMirror).invoke(s, []);
};
});
});
});
}

What is the difference between extends Object with Observable and extends Observable

What is the difference between extends Object with Observable and extends Observable as applied to the class below.
The result is the same when the application is run.
library models;
import 'package:polymer/polymer.dart';
class Person extends Object with Observable {
#observable String name;
#observable bool signedAgreement = false;
Person();
Person.from(Person other) {
name = other.name;
signedAgreement = other.signedAgreement;
}
blank() {
name = '';
signedAgreement = false;
}
}
library models;
import 'package:polymer/polymer.dart';
class Person extends Observable {
#observable String name;
#observable bool signedAgreement = false;
Person();
Person.from(Person other) {
name = other.name;
signedAgreement = other.signedAgreement;
}
blank() {
name = '';
signedAgreement = false;
}
}
There no difference in the behaviour between this two declarations.
Here's a quote from Florian Loitsch :
When you extend "Object" with a mixin the first mixin can always take the place of "Object".
The only little difference is in class hierarchy (superclass are not the same) :
import 'dart:mirrors';
abstract class Mixin {}
class A extends Mixin {}
class B extends Object with Mixin {}
main() {
print(reflectClass(A).superclass);
// => ClassMirror on 'Mixin'
print(reflectClass(A).superclass.superclass);
// => ClassMirror on 'Object'
print(reflectClass(B).superclass);
// => ClassMirror on 'dart.core.Object with .Mixin'
print(reflectClass(B).superclass.superclass);
// => ClassMirror on 'Object'
}

Resources