platform/packages/mirrors/example/reflection_example.dart

284 lines
6.7 KiB
Dart

import 'package:platform_mirrors/mirrors.dart';
// Custom annotation to demonstrate metadata
class Validate {
final String pattern;
const Validate(this.pattern);
}
// Interface to demonstrate reflection with interfaces
@reflectable
abstract class Identifiable {
String get id;
}
// Base class to demonstrate inheritance
@reflectable
abstract class Entity implements Identifiable {
final String _id;
Entity(this._id);
@override
String get id => _id;
@override
String toString() => 'Entity($_id)';
}
// Generic class to demonstrate type parameters
@reflectable
class Container<T> {
final T value;
Container(this.value);
T getValue() => value;
}
@reflectable
class User extends Entity {
@Validate(r'^[a-zA-Z\s]+$')
String name;
int age;
final List<String> tags;
User(String id, this.name, this.age, [this.tags = const []]) : super(id) {
_userCount++;
}
User.guest() : this('guest', 'Guest User', 0);
static int _userCount = 0;
static int get userCount => _userCount;
String greet([String greeting = 'Hello']) {
return '$greeting $name!';
}
void addTag(String tag) {
if (!tags.contains(tag)) {
tags.add(tag);
}
}
String getName() => name;
@override
String toString() =>
'User($id, $name, age: $age)${tags.isNotEmpty ? " [${tags.join(", ")}]" : ""}';
}
void main() async {
// Register classes for reflection
ReflectionRegistry.register(Identifiable);
ReflectionRegistry.register(Entity);
ReflectionRegistry.register(User);
ReflectionRegistry.register(Container);
// Register Container<int> specifically for reflection
final container = Container<int>(42);
ReflectionRegistry.register(container.runtimeType);
// Register property metadata directly
ReflectionRegistry.registerPropertyMetadata(
User,
'name',
PropertyMetadata(
name: 'name',
type: String,
isReadable: true,
isWritable: true,
attributes: [Validate(r'^[a-zA-Z\s]+$')],
),
);
ReflectionRegistry.registerPropertyMetadata(
User,
'age',
PropertyMetadata(
name: 'age',
type: int,
isReadable: true,
isWritable: true,
),
);
ReflectionRegistry.registerPropertyMetadata(
User,
'tags',
PropertyMetadata(
name: 'tags',
type: List,
isReadable: true,
isWritable: false,
),
);
ReflectionRegistry.registerPropertyMetadata(
User,
'id',
PropertyMetadata(
name: 'id',
type: String,
isReadable: true,
isWritable: false,
),
);
// Register User methods
ReflectionRegistry.registerMethod(
User,
'greet',
[String],
false,
parameterNames: ['greeting'],
isRequired: [false],
);
ReflectionRegistry.registerMethod(
User,
'addTag',
[String],
true,
parameterNames: ['tag'],
isRequired: [true],
);
ReflectionRegistry.registerMethod(
User,
'getName',
[],
false,
);
// Register constructors with creators
ReflectionRegistry.registerConstructor(
User,
'',
parameterTypes: [String, String, int, List],
parameterNames: ['id', 'name', 'age', 'tags'],
isRequired: [true, true, true, false],
creator: (id, name, age, [tags]) => User(
id as String,
name as String,
age as int,
tags as List<String>? ?? const [],
),
);
ReflectionRegistry.registerConstructor(
User,
'guest',
creator: () => User.guest(),
);
// Create reflector instance
final reflector = RuntimeReflector.instance;
// Demonstrate generic type reflection
print('Container value: ${container.getValue()}');
try {
// Create User instance using reflection
final user = reflector.createInstance(
User,
positionalArgs: [
'user1',
'John Doe',
30,
['admin', 'user']
],
) as User;
print('\nCreated user: $user');
// Create guest user using named constructor
final guest = reflector.createInstance(
User,
constructorName: 'guest',
) as User;
print('Created guest: $guest');
// Demonstrate property reflection
final userMirror = reflector.reflect(user);
// Get property values
print('\nProperty values:');
print('ID: ${userMirror.getField(const Symbol('id')).reflectee}');
print('Name: ${userMirror.getField(const Symbol('name')).reflectee}');
print('Age: ${userMirror.getField(const Symbol('age')).reflectee}');
print('Tags: ${userMirror.getField(const Symbol('tags')).reflectee}');
// Try to modify properties
userMirror.setField(const Symbol('name'), 'Jane Doe');
userMirror.setField(const Symbol('age'), 25);
print('\nAfter property changes: $user');
// Try to modify read-only property (should throw)
try {
userMirror.setField(const Symbol('id'), 'new_id');
print('ERROR: Should not be able to modify read-only property');
} catch (e) {
print('\nExpected error when modifying read-only property id: $e');
}
// Invoke methods
final greeting = userMirror.invoke(const Symbol('greet'), ['Hi']).reflectee;
print('\nGreeting: $greeting');
userMirror.invoke(const Symbol('addTag'), ['vip']);
print('After adding tag: $user');
final name = userMirror.invoke(const Symbol('getName'), []).reflectee;
print('Got name: $name');
// Demonstrate type metadata and relationships
final userType = reflector.reflectType(User);
print('\nType information:');
print('Type name: ${userType.name}');
// Show available properties
final properties = (userType as dynamic).properties;
print('\nDeclared properties:');
properties.forEach((name, metadata) {
print(
'- $name: ${metadata.type}${metadata.isWritable ? "" : " (read-only)"}');
if (metadata.attributes.isNotEmpty) {
metadata.attributes.forEach((attr) {
if (attr is Validate) {
print(' @Validate(${attr.pattern})');
}
});
}
});
// Show available methods
final methods = (userType as dynamic).methods;
print('\nDeclared methods:');
methods.forEach((name, metadata) {
print('- $name');
});
// Show constructors
final constructors = (userType as dynamic).constructors;
print('\nDeclared constructors:');
constructors.forEach((metadata) {
print('- ${metadata.name}');
});
// Demonstrate type relationships
final identifiableType = reflector.reflectType(Identifiable);
print('\nType relationships:');
print(
'User is assignable to Identifiable: ${userType.isAssignableTo(identifiableType)}');
print(
'User is subtype of Entity: ${userType.isSubtypeOf(reflector.reflectType(Entity))}');
} catch (e) {
print('Error: $e');
print(e.runtimeType);
}
}