platform/packages/reflection
2024-11-29 10:46:16 -07:00
..
doc add: adding reflection package 2024-11-28 16:13:19 -07:00
example update: update reflection package 36 pass 8 fail in testing 2024-11-29 08:37:47 -07:00
lib update: 41 pass 3 fail 2024-11-29 10:46:16 -07:00
test update: update reflection package 36 pass 8 fail in testing 2024-11-29 08:37:47 -07:00
LICENSE add: adding reflection package 2024-11-28 16:13:19 -07:00
pubspec.lock add: adding reflection package 2024-11-28 16:13:19 -07:00
pubspec.yaml update: update reflection package 36 pass 8 fail in testing 2024-11-29 08:37:47 -07:00
README.md update: update reflection package 36 pass 8 fail in testing 2024-11-29 08:37:47 -07:00

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:

dependencies:
  platform_reflection: ^0.1.0

Usage

Basic Reflection

Simply mark your class with @reflectable:

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:

// 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

// 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

// 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

// 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
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 before submitting pull requests.

License

This project is licensed under the MIT License - see the LICENSE file for details.