Note: information on this page refers to Ceylon 1.1, not to the current release.

Annotations

An annotation encodes metadata about a program element.

Usage

Some example annotation constructor declarations:

shared Deprecated deprecated() {
    return Deprecated();
}
shared Description doc(String description) {
    return Description(description);
}
shared Authors by(String* authors) {
    return Authors (*authors);
}

An example of the use of deprecated and by:

deprecated
by("Tom")
class AnnotatedClass() {
}

Description

An annotation is composed of two parts:

  • an annotation class, which is the type of the value that the annotation has when it is obtained at runtime.

  • an annotation constructor, which is used at development time to annotate program elements.

A given annotation class can have zero, one or many annotation constructors.

Annotation class declaration

An annotation class must be a toplevel class annotated with the final and annotation annotations and it must be a direct subclass of either Annotation, OptionalAnnotation or SequencedAnnotation.

final annotation class Example(shared String description) 
        extends Annotation() {
}

Any class parameters must be of one of the allowed types:

  • Integer, Byte, Character, Float, String
  • Enumerated types where all the cases are object declarations (which includes Boolean).
  • A subtype of Declaration
  • Another annotation class.
  • Iterables, Sequences or Tuples of the above.

There are no special constraints on the initialization or declaration sections of an annotation class. In particular the class parameters may be shared or not.

Annotation constructor declaration

An annotation constructor must be a top-level function annotated with annotation, with a return type that is an annotation class.

annotation Example eg() => Example("");
annotation Example example(String description="") 
    => Example(description);

Any parameters must be of one of the permitted types for an annotation class (see above list).

The body of the annotation constructor is quite limited:

  • The only permitted statement is a return statement, whose expression is the instantiation of an annotation class.
  • The arguments to the annotation class instantiation are limited to
    • parameters of the constructor,
    • String, Character, Integer and Float literals,
    • the object cases of parameters of an enumerated type (e.g. true and false),
    • declaration literals (e.g. `class String`)
    • Tuple and Iterable enumerations of the above
    • Spread arguments of the above

Defaulted parameter expressions for constructor parameters are limited by the same rules as the annotation class instantiation arguments.

Constraining Annotations

Annotation classes must be a subclass of Annotation.

  • Using Annotation as the superclass means the annotation class can be used on any program element that supports annotations. The annotation may appear at most once.
  • Annotation has a subclass, ConstrainedAnnotation, which allows more fine-grained control over where and how the annotation may be used. Its enumerated subclasses are:

Program Elements

A ConstrainedAnnotation may constrain the program elements where it is allowed to be used to any of the types satisfying Annotated, which are

Using annotations

To use an annotation you preceed the program element with an invocation of the annotation constructor:

example()
class AnnotatedExample() {
    // ...
}

example("Annotating a function")
void anotherExample() {
}

example{ description = "Annotating a function"; }
String namedArguments => "Good, eh?";

As a special case, and to make it extra easy to write such documentation, annotating program elements with a String literal is a shortcut syntax for annotating the element with the doc annotation.

"Some documentation about [[DocExample]]"
class DocExample() {
    // ...
}

Language module annotations

There is specific documentation on each of the language module annotations

See also