annotate 0.0.3

Annotate #

This provides a set of facades for dealing with annotations in Dart.

Annotations are very useful for reflection, as they allow you to add additional information to declarations. This library provides an easy way to test for and get annotations of specific types. Additional methods have been provided to make it easy to use in where and expand operations on Iterables.

Introduction #

Annotations are constant objects that are applied to declarations. They are available for inspection through the mirrors API.

An example annotation definition looks like:

class ExampleAnnotation {
  const ExampleAnnotation();
}

You can then annotate declarations with it:

@ExampleAnnotation()
class ExampleClass {
    @ExampleAnnotation()
    String exampleField;

    @ExampleAnnotation()
    void exampleMethod() {}

    ...
}

Annotations can take arguments, allowing you to specify details about the specific declaration that has been annotated. For example:

class ExampleSpecificAnnotation {
  final String detail;

  const ExampleSpecificAnnotation(this.detail);
}

To retrieve those details you need to get the annotation object. This is slightly more involved, and it is this step that this library handles.

Synopsis #

Inspect object instances for annotations:

class ExampleAnnotation {
  const ExampleAnnotation();
}

if (new InstanceAnnotationFacade(someObject).hasAnnotationOf(ExampleAnnotation)) {
    doSomething();
}

objectList
  .where(InstanceAnnotationFacade.filterByAnnotation(ExampleAnnotation))
  .forEach((Object instance) {
    doSomething();
  });

Get annotations of objects:

Iterable<ExampleAnnotation> annotations =
  new InstanceAnnotationFacade(someObject).getAnnotationsOf(ExampleAnnotation);

objectList
  .expand(InstanceAnnotationFacade.expandToAnnotations(ExampleAnnotation))
  .forEach((ExampleAnnotation annotation) {
    doSomething();
  });

Inspect types for annotations:

@ExampleAnnotation()
class ExampleType { }

if (new TypeAnnotationFacade(ExampleType).hasAnnotationOf(ExampleAnnotation)) {
  doSomething();
}

typeList
  .where(TypeAnnotationFacade.filterByAnnotation(ExampleAnnotation))
  .forEach((Type type) {
    doSomething();
  });

Get annotations of types:

Iterable<ExampleAnnotation> annotations =
  new TypeAnnotationFacade(ExampleType).getAnnotationsOf(ExampleAnnotation);

typeList
  .expand(TypeAnnotationFacade.expandToAnnotations(ExampleAnnotation))
  .forEach((ExampleAnnotation annotation) {
    doSomething();
  });

Inspect DeclarationMirrors for annotations:

DeclarationMirror mirror = reflect(someObject).type.declarations.values.first; // phew!

if (new DeclarationAnnotationFacade(mirror).hasAnnotationOf(ExampleAnnotation)) {
  doSomething();
}

reflect(someObject).type.declarations.values
  .where(DeclarationAnnotationFacade.filterByAnnotation(ExampleAnnotation))
  .forEach((DeclarationMirror mirror) {
    doSomething();
  });

Get annotations of DeclarationMirrors:

Iterable<ExampleAnnotation> annotations =
  new DeclarationAnnotationFacade(mirror).getAnnotationsOf(ExampleAnnotation);

reflect(someObject).type.declarations.values
  .expand(DeclarationAnnotationFacade.expandToAnnotations(ExampleAnnotation))
  .forEach((ExampleAnnotation annotation) {
    doSomething();
  });

The names are too long! #

Functions are first class objects in Dart, so you can alias the names to something more acceptable:

var filterByAnnotation = InstanceAnnotationFacade.filterByAnnotation(ExampleAnnotation);

objectList.where(filterByAnnotation(ExampleAnnotation))...

The values returned by the filterByAnnotation and expandToAnnotations methods are also methods, and so you can make your aliases even more specific:

var objectFilter = InstanceAnnotationFacade.filterByAnnotation(ExampleAnnotation);

objectList.where(objectFilter)...

Example Code #

Example code is available in the example directory.

example/example.dart

library annotate.example;

import 'dart:mirrors';
import 'package:annotate/annotate.dart';

void main() {
  Iterable<dynamic> objects = [
    new ExampleAnnotatedClass(),
    new ExampleUnannotatedClass()
  ];

  print("When inspecting a list of objects (${describeObjects(objects)})");

  Iterable<dynamic> filteredObjects =
    objects.where(InstanceAnnotationFacade.filterByAnnotation(ExampleAnnotation));

  print("I find that only some objects have the annotation (${describeObjects(filteredObjects)})");

  Iterable<Type> types =
    [ExampleAnnotatedClass, ExampleUnannotatedClass];

  print("When inspecting a list of types (${types.join(", ")})");

  Iterable<Type> filteredTypes =
    types.where(TypeAnnotationFacade.filterByAnnotation(ExampleAnnotation));

  print("I find that only some types have the annotation (${filteredTypes.join(", ")})");

  Iterable<DeclarationMirror> declarations =
    reflect(new ExampleClass()).type.declarations.values;

  print("When inspecting a list of declarations (${declarations.join(", ")})");

  Iterable<DeclarationMirror> filteredDeclarations =
    declarations.where(DeclarationAnnotationFacade.filterByAnnotation(ExampleAnnotation));

  print("I find that only some declarations have the annotation (${filteredDeclarations.join(", ")})");
}

String describeObjects(Iterable<dynamic> objects) =>
  objects.map((o) => o.runtimeType.toString()).join(", ");

class ExampleAnnotation {
  const ExampleAnnotation();
}

const ExampleAnnotation exampleAnnotation = const ExampleAnnotation();


@exampleAnnotation class ExampleAnnotatedClass {}

class ExampleUnannotatedClass {}

class ExampleClass {

  @exampleAnnotation int annotatedField;
  int unannotatedField;

  @exampleAnnotation void annotatedMethod() {}
  void unannotatedMethod() {}
}

// vim: set ai et sw=2 syntax=dart :

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  annotate: ^0.0.3

2. Install it

You can install packages from the command line:

with pub:


$ pub get

Alternatively, your editor might support pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:annotate/annotate.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
4
Health:
Code health derived from static analysis. [more]
--
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
--
Overall:
Weighted score of the above. [more]
2
Learn more about scoring.

The package version is not analyzed, because it does not support Dart 2. Until this is resolved, the package will receive a health and maintenance score of 0.

Analysis issues and suggestions

Support Dart 2 in pubspec.yaml.

The SDK constraint in pubspec.yaml doesn't allow the Dart 2.0.0 release. For information about upgrading it to be Dart 2 compatible, please see https://dart.dev/dart-2#migration.