Annotations
Annotations
In AspectJS, annotations are essentially ECMAScript decorators with no behavior. The role of annotations in AOP is to act as markers, identifying specific elements in your codebase where an aspect can be applied.
In essence, annotations serve as pointcuts that guide the weaver to the corresponding aspects.
Annotations can annotate classes, attributes, static attributes, methods, static methods and method parameters.
warning Annotations cannot be used on functions.
Create an annotation
Annotations can be created with the help of the AnnotationFactory.
The AnnotationFactory
has a group id that identifies your organization and prevents your annotations from colliding with other annotations that could have the same name.
import { AnnotationFactory } from '@aspectjs/common';
// Create an annotation
export const LogErrors = new AnnotationFactory('demo').create(
function LogErrors() {},
);
AnnotationRef
Each annotation has a unique ref
attribute that identifies the annotation. The ref
is build in the form of groupId:annotationName
.
The annotation reference (AnnotationRef) is later used by the weaver to select the advices that correspond to that annotation.
Apply an annotation
Annotations can be applied to various elements in JavaScript, including classes, methods, fields, and parameters, allowing specific sections of code to be marked for enhancement with additional behavior.
class Foo {
@LogErrors()
method1() {
// ...
}
}
AnnotationKind
By default, an annotation created with AnnotationFactory::create
can be used to annotate anything, including classes, methods, properties and parameters.
import { AnnotationFactory } from '@aspectjs/common';
// Create the annotation factory
const af = new AnnotationFactory('demo');
// Create a generic annotation
export const GenericAnnotation = af.create(function GenericAnnotation() {});
@GenericAnnotation()
class X {
@GenericAnnotation()
property1 = 'property1';
@GenericAnnotation()
method1(@GenericAnnotation() arg1: string) {}
}
You can choose to restrict the usage of your annotation by specifying the AnnotationKind to the create
method:
import { AnnotationFactory, AnnotationKind } from '@aspectjs/common';
// Create the annotation factory
const af = new AnnotationFactory('demo');
// Create a class annotation
const ClassAnnotation = af.create(
AnnotationKind.CLASS,
function ClassAnnotation() {},
);
@ClassAnnotation()
class X {
static propperty1 = 'propperty1';
property2 = 'property2';
static method1(arg1: string, arg2: string) {}
method2(arg1: string, arg2: string) {}
}
import { AnnotationFactory, AnnotationKind } from '@aspectjs/common';
// Create the annotation factory
const af = new AnnotationFactory('demo');
// Create a property annotation
const PropertyAnnotation = af.create(
AnnotationKind.PROPERTY,
function PropertyAnnotation() {},
);
class X {
@PropertyAnnotation()
static propperty1 = 'propperty1';
@PropertyAnnotation()
property2 = 'property2';
static method1(arg1: string, arg2: string) {}
method2(arg1: string, arg2: string) {}
}
import { AnnotationFactory, AnnotationKind } from '@aspectjs/common';
// Create the annotation factory
const af = new AnnotationFactory('demo');
// Create a method annotation
const MethodAnnotation = af.create(
AnnotationKind.METHOD,
function MethodAnnotation() {},
);
class X {
static propperty1 = 'propperty1';
property2 = 'property2';
@MethodAnnotation()
static method1(arg1: string, arg2: string) {}
@MethodAnnotation()
method2(arg1: string, arg2: string) {}
}
import { AnnotationFactory, AnnotationKind } from '@aspectjs/common';
// Create the annotation factory
const af = new AnnotationFactory('demo');
// Create a parameter annotation
const ParameterAnnotation = af.create(
AnnotationKind.PARAMETER,
function ParameterAnnotation() {},
);
class X {
static propperty1 = 'propperty1';
property2 = 'property2';
static method1(
@ParameterAnnotation() arg1: string,
@ParameterAnnotation() arg2: string,
) {}
method2(
@ParameterAnnotation() arg1: string,
@ParameterAnnotation() arg2: string,
) {}
}
Annotation parameters
An annotation may accept several parameters. These are defined by the annotation stub (the function) you give to the AnnotationFactory.create()
method:
import { AnnotationFactory, AnnotationKind } from '@aspectjs/common';
// Create the annotation factory
const af = new AnnotationFactory('demo');
// Create a class annotation
const Deprecated = af.create(function Deprecated(
message?: string,
errorsAfterVersion?: string,
) {});
class Connection {
@Deprecated()
hostname: string;
@Deprecated('write port in url instead')
port: number;
@Deprecated('write protocol in url instead', '2.0.0')
protocol: string;
url: string;
}