Skip to main content

11. Annotations

An annotation attaches information to a declaration without changing its structure: the address of a model, the string representation of a concept, the table a concept is stored in. Annotations are how FML carries everything that is not structure, and the way a technology adapter or a tool adds its own information.

11.1 Syntax​

annotation = "@" annotation_tag                                       (* flag *)
| "@" annotation_tag "(" conditional_exp ")" (* single value *)
| "@" annotation_tag "(" key_value ( "," key_value )* ")" (* named values *)
| "@" annotation_tag "(" annotation* ")" (* nested annotations *)

annotation_tag = composite_tident | composite_cident
key_value = composite_ident "=" conditional_exp

The tag is a uidentifier (@Renderer) or a cidentifier (@URI, @UI); it may be qualified by a package path. An annotation has one of four shapes:

@Marker
@Note("hello")
@Owner(name = "Ann", team = "core")
@Groups(
@Member("a")
@Member("b")
)
public model Tagged {
}
  • @Marker is a flag: it says something by being there.
  • @Note("hello") has a value, an expression (a string, a number, a path).
  • @Owner(name = "Ann", team = "core") has named values; each key is a name, each value an expression.
  • @Groups(…) contains annotations: the way a group of related annotations is written. A pair of parentheses with nothing inside is also accepted.

A value is a conditional expression (§9.1): it can use all operators except assignment.

11.2 Placement and retention​

Annotations go before the element they describe: a model, a concept, an event, an enum, a property, a behaviour (any of its forms except that the keyword listen follows its annotations). Several may precede a declaration, in any order. An annotation cannot be attached to a statement, an argument or a local variable.

public model Cards {

@Renderer(name + "!")
public concept Card {

@Hint("on a property")
String name;

create(String name) {
name = parameters.name;
}

@Hint("on a behaviour")
public String greet() {
return "hi";
}
}
}

The platform keeps every annotation it reads, on the element it precedes, and writes it back as it was written, whether it knows the name or not. Annotations are metadata of the declaration, available to any tool that reads the model.

A consequence is that a misspelled annotation is not an error: @Discription is kept like any other and does nothing. Nothing checks the name of an annotation against a list.

11.3 Annotations on a model​

AnnotationValueMeaning
@URI("…")stringthe address of the model (§3.2)
@Version("…")stringits version
@Description("…")stringa short text

They are read back when the model is loaded. A version is normalised: @Version("2") is the version 2.0.

The value of @URI is a string; a namespace alias (§3.3) is not resolved in it (CORE-D-16).

@Description is read on any FML object (the description of a concept, a property or a behaviour is the @Description that precedes it); @Author is read on a concept.

11.4 Annotations on a concept​

AnnotationMeaning
@Renderer(expression)the string representation of the instances of the concept
@Inspector("File.inspector"), @Inspector(derived = …)the inspector of the concept, or a derived inspector (the instance is instance)
@UI("File.fib"), @UI(default = "A.fib", compact = "B.fib")the user-interface component(s) of the concept, overriding the convention

@Renderer. The expression is evaluated on each instance to give its string representation: the text that is obtained when the instance is concatenated to a string, or shown in a browser. It follows the properties it reads, so the representation stays current when they change, and it applies to the concepts that extend the concept. The instance is available as instance, and its properties as bare names.

public model RenderedCards {

@Renderer(name + "!")
public concept Card {
String name;
}

public concept Gold extends Card {
}
}

With name = "x", "" + card is "x!"; after name = "y" it is "y!"; a Gold card inherits the renderer.

@UI and @Inspector. By convention the user interface and the inspector of a concept are files of the container directory (§3.2) named after the concept. The annotations override that convention, naming another file; a multi-valued annotation names variants, the key default being the one used by default.

11.5 Annotations on a behaviour​

AnnotationMeaning
@UI(@Widget(value = "arg", label = "key"), …)how the application asks for the arguments
@Visible(expression)whether the behaviour is offered on an instance; offered when absent
@Enable(expression)whether the behaviour is enabled on an instance

@UI holds one annotation per argument, to choose the widget of the dialog that asks for the argument: value names the argument, label gives the key of its label.

@UI(
@TextField(value = "title", label = "book_title")
)
@Visible(capacity > 0)
public Book newBook(required String title) {
return new Book(parameters.title);
}

@Visible and @Enable are expressions evaluated on the instance (the properties of the concept are in scope); a behaviour is offered, or enabled, when the expression is true.

The dialog exists only in the application. Tests of the platform check that the annotation is loaded, not the dialog.

11.6 Annotations of a technology adapter​

A technology adapter defines annotations for its own needs; the platform keeps them like any other. The relational adapter maps the concepts of a model onto a relational schema:

@Table("CLIENT")
public concept Client {
@Property(column = "ID", id = "true")
int id;
@Property(column = "NAME")
String name;
@Property(column = "SALESMAN", fk = "ID")
Salesman salesman with ConceptInstance();
}

@Table names the table; @Property gives the column (column), marks the identifier (id) and describes a reference to another table (fk, or mappedBy for the other side). The adapters document their own annotations.

11.7 Reading annotations​

Annotations are metadata of the FML object. From a script or a tool, an object reports whether it holds one (hasMetaData("Marker")) and gives its values:

assert virtualModel.hasMetaData("Marker");
assert virtualModel.hasMetaData("Nope") == false;
card = virtualModel.getFlexoConcept("Card");
assert card.hasMetaData("Renderer");