.. | ||
example | ||
lib | ||
test | ||
LICENSE | ||
pubspec.lock | ||
pubspec.yaml | ||
README.md |
Dart Pure Reflection
A lightweight, cross-platform reflection system for Dart that provides runtime type introspection and manipulation without using dart:mirrors
or code generation.
Features
- ✅ Works on all platforms (Web, Mobile, Desktop)
- ✅ No dependency on
dart:mirrors
- ✅ No code generation required
- ✅ Pure runtime reflection
- ✅ Type-safe property access
- ✅ Method invocation with argument validation
- ✅ Constructor invocation support
- ✅ Comprehensive error handling
Installation
Add this to your package's pubspec.yaml
file:
dependencies:
reflection: ^1.0.0
Usage
Basic Setup
- Add the
@reflectable
annotation andReflector
mixin to your class:
import 'package:reflection/reflection.dart';
@reflectable
class User with Reflector {
String name;
int age;
final String id;
User(this.name, this.age, {required this.id});
}
- Register your class and its constructors:
// Register the class
Reflector.register(User);
// Register constructors
Reflector.registerConstructor(
User,
'', // Default constructor
(String name, int age, {String? id}) {
if (id == null) throw ArgumentError.notNull('id');
return User(name, age, id: id);
},
);
Reflecting on Types
final reflector = RuntimeReflector.instance;
// Get type metadata
final userType = reflector.reflectType(User);
print('Type name: ${userType.name}');
print('Properties: ${userType.properties.keys.join(', ')}');
print('Methods: ${userType.methods.keys.join(', ')}');
Working with Instances
final user = User('john_doe', 30, id: 'usr_123');
final userReflector = reflector.reflect(user);
// Read properties
final name = userReflector.getField('name'); // john_doe
final age = userReflector.getField('age'); // 30
// Write properties
userReflector.setField('name', 'jane_doe');
userReflector.setField('age', 25);
// Invoke methods
userReflector.invoke('someMethod', ['arg1', 'arg2']);
Creating Instances
// Using default constructor
final newUser = reflector.createInstance(
User,
positionalArgs: ['alice', 28],
namedArgs: {'id': 'usr_456'},
) as User;
// Using named constructor
final specialUser = reflector.createInstance(
User,
constructorName: 'special',
positionalArgs: ['bob'],
) as User;
Error Handling
The package provides specific exceptions for different error cases:
NotReflectableException
: Thrown when attempting to reflect on a non-reflectable typeReflectionException
: Base class for reflection-related errorsInvalidArgumentsException
: Thrown when providing invalid arguments to a method or constructorMemberNotFoundException
: Thrown when a property or method is not found
try {
reflector.reflect(NonReflectableClass());
} catch (e) {
print(e); // NotReflectableException: Type "NonReflectableClass" is not marked as @reflectable
}
Complete Example
See the example for a complete working demonstration.
Limitations
-
Type Discovery
- Properties and methods must be registered explicitly
- No automatic discovery of class members
- Generic type information is limited
-
Performance
- First access to a type involves metadata creation
- Subsequent accesses use cached metadata
-
Private Members
- Private fields and methods cannot be accessed
- Reflection is limited to public API
Design Philosophy
This package is inspired by:
- dart:mirrors: API design and metadata structure
- fake_reflection: Registration-based approach
- mirrors.cc: Runtime type handling
The goal is to provide a lightweight, cross-platform reflection system that:
- Works everywhere Dart runs
- Requires minimal setup
- Provides type-safe operations
- Maintains good performance
- Follows Dart best practices
Contributing
Contributions are welcome! Please read our contributing guidelines before submitting pull requests.
License
This project is licensed under the MIT License - see the LICENSE file for details.