193 lines
4.8 KiB
Markdown
193 lines
4.8 KiB
Markdown
# Platform Reflection
|
|
|
|
A lightweight, cross-platform reflection system for Dart that provides runtime type introspection and manipulation with an API similar to `dart:mirrors` but without its limitations.
|
|
|
|
## Features
|
|
|
|
- ✅ Works on all platforms (Web, Mobile, Desktop)
|
|
- ✅ No dependency on `dart:mirrors`
|
|
- ✅ Pure runtime reflection
|
|
- ✅ No code generation required
|
|
- ✅ No manual registration needed
|
|
- ✅ Complete mirror-based API
|
|
- ✅ Type-safe property access
|
|
- ✅ Method invocation with argument validation
|
|
- ✅ Constructor invocation support
|
|
- ✅ Library and isolate reflection
|
|
- ✅ Full MirrorSystem implementation
|
|
- ✅ Comprehensive error handling
|
|
|
|
## Installation
|
|
|
|
Add this to your package's `pubspec.yaml` file:
|
|
|
|
```yaml
|
|
dependencies:
|
|
platform_reflection: ^0.1.0
|
|
```
|
|
|
|
## Usage
|
|
|
|
### Basic Reflection
|
|
|
|
Simply mark your class with `@reflectable`:
|
|
|
|
```dart
|
|
import 'package:platform_reflection/reflection.dart';
|
|
|
|
@reflectable
|
|
class User {
|
|
String name;
|
|
int age;
|
|
final String id;
|
|
|
|
User(this.name, this.age, {required this.id});
|
|
|
|
void birthday() {
|
|
age++;
|
|
}
|
|
|
|
String greet(String greeting) {
|
|
return '$greeting, $name!';
|
|
}
|
|
}
|
|
```
|
|
|
|
Then use reflection directly:
|
|
|
|
```dart
|
|
// Get the reflector instance
|
|
final reflector = RuntimeReflector.instance;
|
|
|
|
// Create instance using reflection
|
|
final user = reflector.createInstance(
|
|
User,
|
|
positionalArgs: ['John', 30],
|
|
namedArgs: {'id': '123'},
|
|
) as User;
|
|
|
|
// Get instance mirror
|
|
final mirror = reflector.reflect(user);
|
|
|
|
// Access properties
|
|
print(mirror.getField(const Symbol('name')).reflectee); // John
|
|
print(mirror.getField(const Symbol('age')).reflectee); // 30
|
|
|
|
// Modify properties
|
|
mirror.setField(const Symbol('name'), 'Jane');
|
|
mirror.setField(const Symbol('age'), 25);
|
|
|
|
// Invoke methods
|
|
mirror.invoke(const Symbol('birthday'), []);
|
|
final greeting = mirror.invoke(const Symbol('greet'), ['Hello']).reflectee;
|
|
print(greeting); // Hello, Jane!
|
|
```
|
|
|
|
### Type Information
|
|
|
|
```dart
|
|
// Get mirror system
|
|
final mirrors = reflector.currentMirrorSystem;
|
|
|
|
// Get type mirror
|
|
final typeMirror = mirrors.reflectType(User);
|
|
|
|
// Access type information
|
|
print(typeMirror.name); // User
|
|
print(typeMirror.properties); // {name: PropertyMetadata(...), age: PropertyMetadata(...)}
|
|
print(typeMirror.methods); // {birthday: MethodMetadata(...), greet: MethodMetadata(...)}
|
|
|
|
// Check type relationships
|
|
if (typeMirror.isSubtypeOf(otherType)) {
|
|
print('User is a subtype');
|
|
}
|
|
|
|
// Get declarations
|
|
final declarations = typeMirror.declarations;
|
|
for (var member in declarations.values) {
|
|
if (member is MethodMirror) {
|
|
print('Method: ${member.simpleName}');
|
|
} else if (member is VariableMirror) {
|
|
print('Variable: ${member.simpleName}');
|
|
}
|
|
}
|
|
|
|
// Access special types
|
|
print(mirrors.dynamicType.name); // dynamic
|
|
print(mirrors.voidType.name); // void
|
|
print(mirrors.neverType.name); // Never
|
|
```
|
|
|
|
### Library Reflection
|
|
|
|
```dart
|
|
// Get a library
|
|
final library = mirrors.findLibrary(const Symbol('package:myapp/src/models.dart'));
|
|
|
|
// Access library members
|
|
final declarations = library.declarations;
|
|
for (var decl in declarations.values) {
|
|
print('Declaration: ${decl.simpleName}');
|
|
}
|
|
|
|
// Check imports
|
|
for (var dep in library.libraryDependencies) {
|
|
if (dep.isImport) {
|
|
print('Imports: ${dep.targetLibrary?.uri}');
|
|
}
|
|
}
|
|
```
|
|
|
|
### Isolate Reflection
|
|
|
|
```dart
|
|
// Get current isolate
|
|
final currentIsolate = mirrors.isolate;
|
|
print('Current isolate: ${currentIsolate.debugName}');
|
|
|
|
// Reflect on another isolate
|
|
final isolate = await Isolate.spawn(workerFunction, message);
|
|
final isolateMirror = reflector.reflectIsolate(isolate, 'worker');
|
|
|
|
// Control isolate
|
|
await isolateMirror.pause();
|
|
await isolateMirror.resume();
|
|
await isolateMirror.kill();
|
|
```
|
|
|
|
## Error Handling
|
|
|
|
The package provides specific exceptions for different error cases:
|
|
|
|
- `NotReflectableException`: Thrown when attempting to reflect on a non-reflectable type
|
|
- `ReflectionException`: Base class for reflection-related errors
|
|
- `InvalidArgumentsException`: Thrown when providing invalid arguments to a method or constructor
|
|
- `MemberNotFoundException`: Thrown when a property or method is not found
|
|
|
|
```dart
|
|
try {
|
|
reflect(NonReflectableClass());
|
|
} catch (e) {
|
|
print(e); // NotReflectableException: Type NonReflectableClass is not reflectable
|
|
}
|
|
```
|
|
|
|
## Design Philosophy
|
|
|
|
This package provides a reflection API that closely mirrors the design of `dart:mirrors` while being:
|
|
|
|
- Platform independent
|
|
- Lightweight
|
|
- Type-safe
|
|
- Performant
|
|
- Easy to use
|
|
|
|
The implementation uses pure Dart runtime scanning to provide reflection capabilities across all platforms without requiring code generation or manual registration.
|
|
|
|
## Contributing
|
|
|
|
Contributions are welcome! Please read our [contributing guidelines](CONTRIBUTING.md) before submitting pull requests.
|
|
|
|
## License
|
|
|
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|